Started with code cleanup of Globebrowsing

This commit is contained in:
Alexander Bock
2016-12-04 10:34:25 +01:00
parent 341bc8b105
commit dc3ded891b
84 changed files with 7556 additions and 8083 deletions

View File

@@ -53,7 +53,6 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbylevel.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbyindex.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tilepile.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tile.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/chunktile.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.h
@@ -106,9 +105,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbylevel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbyindex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tilepile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/chunktile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileselector.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tilediskcache.cpp
@@ -126,6 +123,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentjobmanager.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.cpp
${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/threadpool.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})

View File

@@ -22,193 +22,190 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <ghoul/misc/assert.h>
#include <openspace/engine/openspaceengine.h>
#include <modules/globebrowsing/chunk/chunk.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/rendering/layermanager.h>
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/tile/tileselector.h>
#include <algorithm>
namespace {
const std::string _loggerCat = "Chunk";
}
namespace openspace {
namespace globebrowsing {
const float Chunk::DEFAULT_HEIGHT = 0.0f;
const float Chunk::DEFAULT_HEIGHT = 0.0f;
Chunk::Chunk(
const RenderableGlobe& owner,
const TileIndex& tileIndex,
bool initVisible)
: _owner(owner)
, _surfacePatch(tileIndex)
, _tileIndex(tileIndex)
, _isVisible(initVisible)
{ }
Chunk::Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex, bool initVisible)
: _owner(owner)
, _surfacePatch(tileIndex)
, _tileIndex(tileIndex)
, _isVisible(initVisible)
{}
const GeodeticPatch& Chunk::surfacePatch() const {
return _surfacePatch;
const GeodeticPatch& Chunk::surfacePatch() const {
return _surfacePatch;
}
const RenderableGlobe& Chunk::owner() const {
return _owner;
}
const TileIndex Chunk::tileIndex() const {
return _tileIndex;
}
bool Chunk::isVisible() const {
return _isVisible;
}
Chunk::Status Chunk::update(const RenderData& data) {
auto savedCamera = _owner.savedCamera();
const Camera& camRef = savedCamera != nullptr ? *savedCamera : data.camera;
RenderData myRenderData = { camRef, data.position, data.doPerformanceMeasurement };
_isVisible = true;
if (_owner.chunkedLodGlobe()->testIfCullable(*this, myRenderData)) {
_isVisible = false;
return Status::WANT_MERGE;
}
const RenderableGlobe& Chunk::owner() const {
return _owner;
int desiredLevel = _owner.chunkedLodGlobe()->getDesiredLevel(*this, myRenderData);
if (desiredLevel < _tileIndex.level) {
return Status::WANT_MERGE;
}
const TileIndex Chunk::tileIndex() const {
return _tileIndex;
else if (_tileIndex.level < desiredLevel) {
return Status::WANT_SPLIT;
}
bool Chunk::isVisible() const {
return _isVisible;
else {
return Status::DO_NOTHING;
}
}
Chunk::Status Chunk::update(const RenderData& data) {
auto savedCamera = _owner.savedCamera();
const Camera& camRef =
savedCamera != nullptr ? *savedCamera : data.camera;
RenderData myRenderData =
{ camRef, data.position, data.doPerformanceMeasurement };
Chunk::BoundingHeights Chunk::getBoundingHeights() const {
BoundingHeights boundingHeights;
boundingHeights.max = 0;
boundingHeights.min = 0;
boundingHeights.available = false;
_isVisible = true;
if (_owner.chunkedLodGlobe()->testIfCullable(*this, myRenderData)) {
_isVisible = false;
return Status::WANT_MERGE;
}
int desiredLevel = _owner.chunkedLodGlobe()->getDesiredLevel(*this, myRenderData);
if (desiredLevel < _tileIndex.level) return Status::WANT_MERGE;
else if (_tileIndex.level < desiredLevel) return Status::WANT_SPLIT;
else return Status::DO_NOTHING;
}
Chunk::BoundingHeights Chunk::getBoundingHeights() const {
BoundingHeights boundingHeights;
boundingHeights.max = 0;
boundingHeights.min = 0;
boundingHeights.available = false;
// In the future, this should be abstracted away and more easily queryable.
// One must also handle how to sample pick one out of multiplte heightmaps
auto layerManager = owner().chunkedLodGlobe()->layerManager();
// In the future, this should be abstracted away and more easily queryable.
// One must also handle how to sample pick one out of multiplte heightmaps
auto layerManager = owner().chunkedLodGlobe()->layerManager();
// The raster of a height map is the first one. We assume that the height map is
// a single raster image. If it is not we will just use the first raster
// (that is channel 0).
size_t HEIGHT_CHANNEL = 0;
const LayerGroup& heightmaps =
layerManager->layerGroup(LayerManager::HeightLayers);
std::vector<ChunkTile> chunkTiles =
TileSelector::getTilesSortedByHighestResolution(heightmaps, _tileIndex);
bool lastHadMissingData = true;
for (auto chunkTile : chunkTiles) {
bool goodTile = chunkTile.tile.status == Tile::Status::OK;
bool hastileMetaData = chunkTile.tile.metaData != nullptr;
// The raster of a height map is the first one. We assume that the height map is
// a single raster image. If it is not we will just use the first raster
// (that is channel 0).
size_t HEIGHT_CHANNEL = 0;
const LayerGroup& heightmaps = layerManager->layerGroup(LayerManager::HeightLayers);
std::vector<ChunkTile> chunkTiles = TileSelector::getTilesSortedByHighestResolution(
heightmaps, _tileIndex
);
if (goodTile && hastileMetaData) {
auto tileMetaData = chunkTile.tile.metaData;
bool lastHadMissingData = true;
for (auto chunkTile : chunkTiles) {
bool goodTile = chunkTile.tile.status == Tile::Status::OK;
bool hastileMetaData = chunkTile.tile.metaData != nullptr;
if (!boundingHeights.available) {
if (tileMetaData->hasMissingData[HEIGHT_CHANNEL]) {
boundingHeights.min = std::min(
DEFAULT_HEIGHT, tileMetaData->minValues[HEIGHT_CHANNEL]);
boundingHeights.max = std::max(
DEFAULT_HEIGHT, tileMetaData->maxValues[HEIGHT_CHANNEL]);
}
else {
boundingHeights.min = tileMetaData->minValues[HEIGHT_CHANNEL];
boundingHeights.max = tileMetaData->maxValues[HEIGHT_CHANNEL];
}
boundingHeights.available = true;
if (goodTile && hastileMetaData) {
auto tileMetaData = chunkTile.tile.metaData;
if (!boundingHeights.available) {
if (tileMetaData->hasMissingData[HEIGHT_CHANNEL]) {
boundingHeights.min = std::min(
DEFAULT_HEIGHT,
tileMetaData->minValues[HEIGHT_CHANNEL]
);
boundingHeights.max = std::max(
DEFAULT_HEIGHT,
tileMetaData->maxValues[HEIGHT_CHANNEL]
);
}
else {
boundingHeights.min = std::min(
boundingHeights.min, tileMetaData->minValues[HEIGHT_CHANNEL]);
boundingHeights.max = std::max(
boundingHeights.max, tileMetaData->maxValues[HEIGHT_CHANNEL]);
boundingHeights.min = tileMetaData->minValues[HEIGHT_CHANNEL];
boundingHeights.max = tileMetaData->maxValues[HEIGHT_CHANNEL];
}
lastHadMissingData = tileMetaData->hasMissingData[HEIGHT_CHANNEL];
boundingHeights.available = true;
}
// Allow for early termination
if (!lastHadMissingData) {
break;
else {
boundingHeights.min = std::min(
boundingHeights.min,
tileMetaData->minValues[HEIGHT_CHANNEL]
);
boundingHeights.max = std::max(
boundingHeights.max,
tileMetaData->maxValues[HEIGHT_CHANNEL]
);
}
lastHadMissingData = tileMetaData->hasMissingData[HEIGHT_CHANNEL];
}
// Allow for early termination
if (!lastHadMissingData) {
break;
}
return boundingHeights;
}
std::vector<glm::dvec4> Chunk::getBoundingPolyhedronCorners() const {
const Ellipsoid& ellipsoid = owner().ellipsoid();
const GeodeticPatch& patch = surfacePatch();
BoundingHeights boundingHeight = getBoundingHeights();
// assume worst case
double patchCenterRadius = ellipsoid.maximumRadius();
double maxCenterRadius = patchCenterRadius + boundingHeight.max;
Geodetic2 halfSize = patch.halfSize();
// As the patch is curved, the maximum height offsets at the corners must be long
// enough to cover large enough to cover a boundingHeight.max at the center of the
// patch.
// Approximating scaleToCoverCenter by assuming the latitude and longitude angles
// of "halfSize" are equal to the angles they create from the center of the
// globe to the patch corners. This is true for the longitude direction when
// the ellipsoid can be approximated as a sphere and for the latitude for patches
// close to the equator. Close to the pole this will lead to a bigger than needed
// value for scaleToCoverCenter. However, this is a simple calculation and a good
// Approximation.
double y1 = tan(halfSize.lat);
double y2 = tan(halfSize.lon);
double scaleToCoverCenter = sqrt(1 + pow(y1, 2) + pow(y2, 2));
double maxCornerHeight = maxCenterRadius * scaleToCoverCenter - patchCenterRadius;
return boundingHeights;
}
bool chunkIsNorthOfEquator = patch.isNorthern();
std::vector<glm::dvec4> Chunk::getBoundingPolyhedronCorners() const {
const Ellipsoid& ellipsoid = owner().ellipsoid();
const GeodeticPatch& patch = surfacePatch();
// The minimum height offset, however, we can simply
double minCornerHeight = boundingHeight.min;
std::vector<glm::dvec4> corners(8);
BoundingHeights boundingHeight = getBoundingHeights();
// assume worst case
double patchCenterRadius = ellipsoid.maximumRadius();
double maxCenterRadius = patchCenterRadius + boundingHeight.max;
Geodetic2 halfSize = patch.halfSize();
// As the patch is curved, the maximum height offsets at the corners must be long
// enough to cover large enough to cover a boundingHeight.max at the center of the
// patch.
// Approximating scaleToCoverCenter by assuming the latitude and longitude angles
// of "halfSize" are equal to the angles they create from the center of the
// globe to the patch corners. This is true for the longitude direction when
// the ellipsoid can be approximated as a sphere and for the latitude for patches
// close to the equator. Close to the pole this will lead to a bigger than needed
// value for scaleToCoverCenter. However, this is a simple calculation and a good
// Approximation.
double y1 = tan(halfSize.lat);
double y2 = tan(halfSize.lon);
double scaleToCoverCenter = sqrt(1 + pow(y1, 2) + pow(y2, 2));
Scalar latCloseToEquator = patch.edgeLatitudeNearestEquator();
Geodetic3 p1Geodetic = { { latCloseToEquator, patch.minLon() }, maxCornerHeight };
Geodetic3 p2Geodetic = { { latCloseToEquator, patch.maxLon() }, maxCornerHeight };
glm::vec3 p1 = ellipsoid.cartesianPosition(p1Geodetic);
glm::vec3 p2 = ellipsoid.cartesianPosition(p2Geodetic);
glm::vec3 p = 0.5f * (p1 + p2);
Geodetic2 pGeodetic = ellipsoid.cartesianToGeodetic2(p);
Scalar latDiff = latCloseToEquator - pGeodetic.lat;
double maxCornerHeight = maxCenterRadius * scaleToCoverCenter - patchCenterRadius;
for (size_t i = 0; i < 8; i++) {
Quad q = (Quad)(i % 4);
double cornerHeight = i < 4 ? minCornerHeight : maxCornerHeight;
Geodetic3 cornerGeodetic = { patch.getCorner(q), cornerHeight };
bool chunkIsNorthOfEquator = patch.isNorthern();
// The minimum height offset, however, we can simply
double minCornerHeight = boundingHeight.min;
std::vector<glm::dvec4> corners(8);
double latCloseToEquator = patch.edgeLatitudeNearestEquator();
Geodetic3 p1Geodetic = { { latCloseToEquator, patch.minLon() }, maxCornerHeight };
Geodetic3 p2Geodetic = { { latCloseToEquator, patch.maxLon() }, maxCornerHeight };
glm::vec3 p1 = ellipsoid.cartesianPosition(p1Geodetic);
glm::vec3 p2 = ellipsoid.cartesianPosition(p2Geodetic);
glm::vec3 p = 0.5f * (p1 + p2);
Geodetic2 pGeodetic = ellipsoid.cartesianToGeodetic2(p);
double latDiff = latCloseToEquator - pGeodetic.lat;
for (size_t i = 0; i < 8; ++i) {
Quad q = (Quad)(i % 4);
double cornerHeight = i < 4 ? minCornerHeight : maxCornerHeight;
Geodetic3 cornerGeodetic = { patch.getCorner(q), cornerHeight };
bool cornerIsNorthern = !((i / 2) % 2);
bool cornerCloseToEquator = chunkIsNorthOfEquator ^ cornerIsNorthern;
if (cornerCloseToEquator) {
cornerGeodetic.geodetic2.lat += latDiff;
}
corners[i] = dvec4(ellipsoid.cartesianPosition(cornerGeodetic), 1);
bool cornerIsNorthern = !((i / 2) % 2);
bool cornerCloseToEquator = chunkIsNorthOfEquator ^ cornerIsNorthern;
if (cornerCloseToEquator) {
cornerGeodetic.geodetic2.lat += latDiff;
}
return corners;
corners[i] = glm::dvec4(ellipsoid.cartesianPosition(cornerGeodetic), 1);
}
return corners;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -22,93 +22,86 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CHUNK_H__
#define __CHUNK_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_H__
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <ostream>
#include <modules/globebrowsing/chunk/culling.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/geometry/angle.h>
namespace openspace {
struct RenderData;
namespace globebrowsing {
class RenderableGlobe;
class GeodeticPatch;
class RenderableGlobe;
struct TileIndex;
class Chunk {
public:
const static float DEFAULT_HEIGHT;
class Chunk {
public:
const static float DEFAULT_HEIGHT;
struct BoundingHeights {
float min, max;
bool available;
};
enum class Status {
DO_NOTHING,
WANT_MERGE,
WANT_SPLIT,
};
Chunk(
const RenderableGlobe& owner,
const TileIndex& tileIndex,
bool initVisible = true);
/**
* Updates the Chunk internally and returns the Status of the Chunk.
*
* Tests if the Chunk is cullable and gets the desired level of the Chunk. If the
* Chunk is cullable it will be set to invisible and return Status::WANT_MERGE.
* If the desired level is smaller than the current level of the chunk it will
* return Status::WANT_MERGE, if it is larger it will return Status::WANT_SPLIT,
* otherwise Status::DO_NOTHING.
*
* \returns The Status of the chunk.
*/
Status update(const RenderData& data);
/**
* Returns a convex polyhedron of eight vertices tightly bounding the volume of
* the Chunk.
*/
std::vector<glm::dvec4> getBoundingPolyhedronCorners() const;
const GeodeticPatch& surfacePatch() const;
const RenderableGlobe& owner() const;
const TileIndex tileIndex() const;
bool isVisible() const;
/**
* Returns BoundingHeights that fits the Chunk as tightly as possible.
*
* If the Chunk uses more than one HightLayer, the BoundingHeights will be set
* to cover all HightLayers. If the Chunk has a higher level than its highest
* resolution HightLayer Tile, it will base its BoundingHeights on that Tile.
* This means that high level Chunks can have BoundingHeights that are not
* tightly fitting.
*/
BoundingHeights getBoundingHeights() const;
private:
const RenderableGlobe& _owner;
const TileIndex _tileIndex;
bool _isVisible;
const GeodeticPatch _surfacePatch;
struct BoundingHeights {
float min, max;
bool available;
};
enum class Status {
DO_NOTHING,
WANT_MERGE,
WANT_SPLIT,
};
Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex,
bool initVisible = true);
/**
* Updates the Chunk internally and returns the Status of the Chunk.
*
* Tests if the Chunk is cullable and gets the desired level of the Chunk. If the
* Chunk is cullable it will be set to invisible and return Status::WANT_MERGE.
* If the desired level is smaller than the current level of the chunk it will
* return Status::WANT_MERGE, if it is larger it will return Status::WANT_SPLIT,
* otherwise Status::DO_NOTHING.
*
* \returns The Status of the chunk.
*/
Status update(const RenderData& data);
/**
* Returns a convex polyhedron of eight vertices tightly bounding the volume of
* the Chunk.
*/
std::vector<glm::dvec4> getBoundingPolyhedronCorners() const;
const GeodeticPatch& surfacePatch() const;
const RenderableGlobe& owner() const;
const TileIndex tileIndex() const;
bool isVisible() const;
/**
* Returns BoundingHeights that fits the Chunk as tightly as possible.
*
* If the Chunk uses more than one HightLayer, the BoundingHeights will be set
* to cover all HightLayers. If the Chunk has a higher level than its highest
* resolution HightLayer Tile, it will base its BoundingHeights on that Tile.
* This means that high level Chunks can have BoundingHeights that are not
* tightly fitting.
*/
BoundingHeights getBoundingHeights() const;
private:
const RenderableGlobe& _owner;
const TileIndex _tileIndex;
bool _isVisible;
const GeodeticPatch _surfacePatch;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __CHUNK_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_H__

View File

@@ -22,179 +22,166 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <ghoul/misc/assert.h>
#include <openspace/engine/openspaceengine.h>
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
#include <modules/globebrowsing/chunk/chunk.h>
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/rendering/layermanager.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/rendering/layermanager.h>
#include <algorithm>
namespace {
const std::string _loggerCat = "ChunkLevelEvaluator";
}
namespace openspace {
namespace globebrowsing {
int EvaluateChunkLevelByDistance::getDesiredLevel(
const Chunk& chunk,
const RenderData& data) const {
// Calculations are done in the reference frame of the globe
// (model space). Hence, the camera position needs to be transformed
// with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
const RenderableGlobe& globe = chunk.owner();
const Ellipsoid& ellipsoid = globe.ellipsoid();
int EvaluateChunkLevelByDistance::getDesiredLevel(const Chunk& chunk,
const RenderData& data) const
{
// Calculations are done in the reference frame of the globe
// (model space). Hence, the camera position needs to be transformed
// with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
const RenderableGlobe& globe = chunk.owner();
const Ellipsoid& ellipsoid = globe.ellipsoid();
Vec3 cameraPosition =
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
glm::dvec3 cameraPosition =
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
Geodetic2 pointOnPatch = chunk.surfacePatch().closestPoint(
ellipsoid.cartesianToGeodetic2(cameraPosition));
Vec3 patchNormal = ellipsoid.geodeticSurfaceNormal(pointOnPatch);
Vec3 patchPosition = ellipsoid.cartesianSurfacePosition(pointOnPatch);
Geodetic2 pointOnPatch = chunk.surfacePatch().closestPoint(
ellipsoid.cartesianToGeodetic2(cameraPosition)
);
glm::dvec3 patchNormal = ellipsoid.geodeticSurfaceNormal(pointOnPatch);
glm::dvec3 patchPosition = ellipsoid.cartesianSurfacePosition(pointOnPatch);
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
Scalar heightToChunk = heights.min;
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
double heightToChunk = heights.min;
// Offset position according to height
patchPosition += patchNormal * heightToChunk;
// Offset position according to height
patchPosition += patchNormal * heightToChunk;
Vec3 cameraToChunk = patchPosition - cameraPosition;
glm::dvec3 cameraToChunk = patchPosition - cameraPosition;
// Calculate desired level based on distance
Scalar distanceToPatch = glm::length(cameraToChunk);
Scalar distance = distanceToPatch;
// Calculate desired level based on distance
double distanceToPatch = glm::length(cameraToChunk);
double distance = distanceToPatch;
Scalar scaleFactor =
globe.generalProperties().lodScaleFactor * ellipsoid.minimumRadius();
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = ceil(log2(projectedScaleFactor));
return desiredLevel;
}
double scaleFactor =
globe.generalProperties().lodScaleFactor * ellipsoid.minimumRadius();
double projectedScaleFactor = scaleFactor / distance;
int desiredLevel = ceil(log2(projectedScaleFactor));
return desiredLevel;
}
int EvaluateChunkLevelByProjectedArea::getDesiredLevel(
const Chunk& chunk,
const RenderData& data) const {
// Calculations are done in the reference frame of the globe
// (model space). Hence, the camera position needs to be transformed
// with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
int EvaluateChunkLevelByProjectedArea::getDesiredLevel(const Chunk& chunk,
const RenderData& data) const
{
// Calculations are done in the reference frame of the globe
// (model space). Hence, the camera position needs to be transformed
// with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
const RenderableGlobe& globe = chunk.owner();
const Ellipsoid& ellipsoid = globe.ellipsoid();
glm::dvec4 cameraPositionModelSpace = glm::dvec4(data.camera.positionVec3(), 1);
Vec3 cameraPosition =
glm::dvec3(inverseModelTransform * cameraPositionModelSpace);
Vec3 cameraToEllipsoidCenter = -cameraPosition;
const RenderableGlobe& globe = chunk.owner();
const Ellipsoid& ellipsoid = globe.ellipsoid();
glm::dvec4 cameraPositionModelSpace = glm::dvec4(data.camera.positionVec3(), 1);
glm::dvec3 cameraPosition =
glm::dvec3(inverseModelTransform * cameraPositionModelSpace);
glm::dvec3 cameraToEllipsoidCenter = -cameraPosition;
Geodetic2 cameraGeodeticPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
Geodetic2 cameraGeodeticPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
// Approach:
// The projected area of the chunk will be calculated based on a small area that
// is close to the camera, and the scaled up to represent the full area.
// The advantage of doing this is that it will better handle the cases where the
// full patch is very curved (e.g. stretches from latitude 0 to 90 deg).
// Approach:
// The projected area of the chunk will be calculated based on a small area that
// is close to the camera, and the scaled up to represent the full area.
// The advantage of doing this is that it will better handle the cases where the
// full patch is very curved (e.g. stretches from latitude 0 to 90 deg).
const Geodetic2 center = chunk.surfacePatch().center();
const Geodetic2 closestCorner =
chunk.surfacePatch().closestCorner(cameraGeodeticPos);
const Geodetic2 center = chunk.surfacePatch().center();
const Geodetic2 closestCorner = chunk.surfacePatch().closestCorner(cameraGeodeticPos);
// Camera
// |
// V
//
// oo
// [ ]<
// *geodetic space*
//
// closestCorner
// +-----------------+ <-- north east corner
// | |
// | center |
// | |
// +-----------------+ <-- south east corner
// Camera
// |
// V
//
// oo
// [ ]<
// *geodetic space*
//
// closestCorner
// +-----------------+ <-- north east corner
// | |
// | center |
// | |
// +-----------------+ <-- south east corner
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
const Geodetic3 c = { center, heights.min };
const Geodetic3 c1 = { Geodetic2(center.lat, closestCorner.lon), heights.min };
const Geodetic3 c2 = { Geodetic2(closestCorner.lat, center.lon), heights.min };
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
const Geodetic3 c = { center, heights.min };
const Geodetic3 c1 = { Geodetic2(center.lat, closestCorner.lon), heights.min };
const Geodetic3 c2 = { Geodetic2(closestCorner.lat, center.lon), heights.min };
// Camera
// |
// V
//
// oo
// [ ]<
// *geodetic space*
//
// +--------c2-------+ <-- north east corner
// | |
// c1 c |
// | |
// +-----------------+ <-- south east corner
// Camera
// |
// V
//
// oo
// [ ]<
// *geodetic space*
//
// +--------c2-------+ <-- north east corner
// | |
// c1 c |
// | |
// +-----------------+ <-- south east corner
// Go from geodetic to cartesian space
Vec3 A = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c);
Vec3 B = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c1);
Vec3 C = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c2);
// Go from geodetic to cartesian space
glm::dvec3 A = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c);
glm::dvec3 B = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c1);
glm::dvec3 C = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c2);
// Project onto unit sphere
A = glm::normalize(A);
B = glm::normalize(B);
C = glm::normalize(C);
// Project onto unit sphere
A = glm::normalize(A);
B = glm::normalize(B);
C = glm::normalize(C);
// Camera *cartesian space*
// | +--------+---+
// V __--'' __--'' /
// C-------A--------- +
// oo / / /
//[ ]< +-------B----------+
//
// Camera *cartesian space*
// | +--------+---+
// V __--'' __--'' /
// C-------A--------- +
// oo / / /
//[ ]< +-------B----------+
//
// If the geodetic patch is small (i.e. has small width), that means the patch in
// cartesian space will be almost flat, and in turn, the triangle ABC will roughly
// correspond to 1/8 of the full area
const Vec3 AB = B - A;
const Vec3 AC = C - A;
double areaABC = 0.5 * glm::length(glm::cross(AC, AB));
double projectedChunkAreaApprox = 8 * areaABC;
// If the geodetic patch is small (i.e. has small width), that means the patch in
// cartesian space will be almost flat, and in turn, the triangle ABC will roughly
// correspond to 1/8 of the full area
const glm::dvec3 AB = B - A;
const glm::dvec3 AC = C - A;
double areaABC = 0.5 * glm::length(glm::cross(AC, AB));
double projectedChunkAreaApprox = 8 * areaABC;
double scaledArea =
globe.generalProperties().lodScaleFactor * projectedChunkAreaApprox;
return chunk.tileIndex().level + round(scaledArea - 1);
}
double scaledArea =
globe.generalProperties().lodScaleFactor * projectedChunkAreaApprox;
return chunk.tileIndex().level + round(scaledArea - 1);
}
int EvaluateChunkLevelByAvailableTileData::getDesiredLevel(
const Chunk& chunk,
const RenderData& data) const {
auto layerManager = chunk.owner().chunkedLodGlobe()->layerManager();
auto heightLayers = layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
int currLevel = chunk.tileIndex().level;
int EvaluateChunkLevelByAvailableTileData::getDesiredLevel(const Chunk& chunk,
const RenderData& data) const
{
auto layerManager = chunk.owner().chunkedLodGlobe()->layerManager();
auto heightLayers = layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
int currLevel = chunk.tileIndex().level;
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; i++) {
for (auto& layer : layerManager->layerGroup(i).activeLayers()) {
Tile::Status tileStatus =
layer->tileProvider()->getTileStatus(chunk.tileIndex());
if (tileStatus == Tile::Status::OK) {
return UNKNOWN_DESIRED_LEVEL;
}
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; ++i) {
for (auto& layer : layerManager->layerGroup(i).activeLayers()) {
Tile::Status tileStatus =
layer->tileProvider()->getTileStatus(chunk.tileIndex());
if (tileStatus == Tile::Status::OK) {
return UNKNOWN_DESIRED_LEVEL;
}
}
return currLevel - 1;
}
return currLevel - 1;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -22,61 +22,61 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CHUNK_LEVEL_EVALUATOR_H__
#define __CHUNK_LEVEL_EVALUATOR_H__
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <ostream>
#include <modules/globebrowsing/chunk/chunk.h>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKLEVELEVALUATOR_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKLEVELEVALUATOR_H__
namespace openspace {
struct RenderData;
namespace globebrowsing {
/**
* Abstract class defining an interface for accessing a desired level of a Chunk.
* The desired level can be used in the process of determining whether a Chunk should
* want to split, merge or do nothing.
*/
class ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const = 0;
static const int UNKNOWN_DESIRED_LEVEL = -1;
};
/**
* Evaluate the Chunk level depending on the distance from the Camera to the Chunk.
* This evaluation method aims to keep the screen size (horizontal length and not
* area) of all chunks constant.
*/
class EvaluateChunkLevelByDistance : public ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
class Chunk;
/**
* Evaluate the chunk level using the area of the non-heightmapped Chunk projected
* on a sphere with the center in the position of the camera. A Chunk near the
* horizon will have a small projected area and hence a lower desired level. This
* evaluation is more forgiving than EvaluateChunkLevelByDistance, meaning it results
* in lower desired levels.
*/
class EvaluateChunkLevelByProjectedArea : public ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
/**
* Abstract class defining an interface for accessing a desired level of a Chunk.
* The desired level can be used in the process of determining whether a Chunk should
* want to split, merge or do nothing.
*/
class ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const = 0;
static const int UNKNOWN_DESIRED_LEVEL = -1;
};
/**
* Evaluate the Chunk level depending on the distance from the Camera to the Chunk.
* This evaluation method aims to keep the screen size (horizontal length and not
* area) of all chunks constant.
*/
class EvaluateChunkLevelByDistance : public ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
/**
* Evaluate the chunk level using the area of the non-heightmapped Chunk projected
* on a sphere with the center in the position of the camera. A Chunk near the
* horizon will have a small projected area and hence a lower desired level. This
* evaluation is more forgiving than EvaluateChunkLevelByDistance, meaning it results
* in lower desired levels.
*/
class EvaluateChunkLevelByProjectedArea : public ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
/**
* If this chunk has available tile data for any LayerGroup on any of its active
* Layers it will return an UNKNOWN_DESIRED_LEVEL. If no data is available it will
* evaluate to a level that is <code>current level -1</code>.
*/
class EvaluateChunkLevelByAvailableTileData : public ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
/**
* If this chunk has available tile data for any LayerGroup on any of its active
* Layers it will return an UNKNOWN_DESIRED_LEVEL. If no data is available it will
* evaluate to a level that is <code>current level -1</code>.
*/
class EvaluateChunkLevelByAvailableTileData : public ChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __CHUNK_LEVEL_EVALUATOR_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKLEVELEVALUATOR_H__

View File

@@ -22,20 +22,12 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <queue>
#include <modules/globebrowsing/chunk/chunknode.h>
#include <ghoul/misc/assert.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/engine/openspaceengine.h>
#include <modules/globebrowsing/chunk/chunknode.h>
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/chunk/culling.h>
namespace {
const std::string _loggerCat = "ChunkNode";
}
#include <stack>
#include <queue>
namespace openspace {
namespace globebrowsing {
@@ -43,13 +35,10 @@ namespace globebrowsing {
int ChunkNode::chunkNodeCount = 0;
ChunkNode::ChunkNode(const Chunk& chunk, ChunkNode* parent)
: _chunk(chunk)
, _parent(parent)
: _chunk(chunk)
, _parent(parent)
, _children({ nullptr, nullptr, nullptr, nullptr })
{
_children[0] = nullptr;
_children[1] = nullptr;
_children[2] = nullptr;
_children[3] = nullptr;
chunkNodeCount++;
}
@@ -121,8 +110,8 @@ void ChunkNode::breadthFirst(const std::function<void(const ChunkNode&)>& f) con
}
}
void ChunkNode::reverseBreadthFirst(
const std::function<void(const ChunkNode&)>& f) const {
void ChunkNode::reverseBreadthFirst(const std::function<void(const ChunkNode&)>& f) const
{
std::stack<const ChunkNode*> S;
std::queue<const ChunkNode*> Q;
@@ -137,9 +126,12 @@ void ChunkNode::reverseBreadthFirst(
// Add children to queue, if any
if (!node->isLeaf()) {
for (int i = 0; i < 4; ++i) {
Q.push(node->_children[i].get());
for (const auto& c : node->_children) {
Q.push(c.get());
}
//for (int i = 0; i < 4; ++i) {
// Q.push(node->_children[i].get());
//}
}
}
@@ -150,23 +142,21 @@ void ChunkNode::reverseBreadthFirst(
}
}
#define CHUNK_NODE_FIND(node, p) \
while (!node->isLeaf()) { \
const Geodetic2 center = node->_chunk.surfacePatch().center();\
int index = 0;\
if (center.lon < p.lon) {\
++index;\
}\
if (p.lat < center.lat) {\
++index;\
++index;\
}\
node = &(node->getChild((Quad)index));\
}
const ChunkNode& ChunkNode::find(const Geodetic2& location) const {
const ChunkNode* node = this;
CHUNK_NODE_FIND(node, location);
while (!node->isLeaf()) {
const Geodetic2 center = node->_chunk.surfacePatch().center();
int index = 0;
if (center.lon < location.lon) {
++index;
}
if (location.lat < center.lat) {
++index;
++index;
}
node = &(node->getChild((Quad)index));
}
return *node;
}
@@ -176,21 +166,21 @@ const ChunkNode& ChunkNode::getChild(Quad quad) const {
void ChunkNode::split(int depth) {
if (depth > 0 && isLeaf()) {
for (size_t i = 0; i < 4; i++) {
for (size_t i = 0; i < _children.size(); i++) {
Chunk chunk(_chunk.owner(), _chunk.tileIndex().child((Quad)i));
_children[i] = std::make_unique<ChunkNode>(chunk, this);
}
}
if (depth - 1 > 0) {
for (int i = 0; i < 4; ++i) {
for (int i = 0; i < _children.size(); ++i) {
_children[i]->split(depth - 1);
}
}
}
void ChunkNode::merge() {
for (int i = 0; i < 4; ++i) {
for (int i = 0; i < _children.size(); ++i) {
if (_children[i] != nullptr) {
_children[i]->merge();
}

View File

@@ -22,20 +22,14 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __QUADTREE_H__
#define __QUADTREE_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKNODE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKNODE_H__
#include <glm/glm.hpp>
#include <vector>
#include <stack>
#include <memory>
#include <ostream>
#include <functional>
#include <modules/globebrowsing/tile/tileindex.h>
#include <modules/globebrowsing/chunk/chunk.h>
#include <modules/globebrowsing/rendering/chunkrenderer.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <array>
#include <functional>
#include <memory>
namespace openspace {
namespace globebrowsing {
@@ -63,9 +57,9 @@ public:
bool isRoot() const;
bool isLeaf() const;
void depthFirst( const std::function<void(const ChunkNode&)>& f) const;
void breadthFirst( const std::function<void(const ChunkNode&)>& f) const;
void reverseBreadthFirst( const std::function<void(const ChunkNode&)>& f) const;
void depthFirst(const std::function<void(const ChunkNode&)>& f) const;
void breadthFirst(const std::function<void(const ChunkNode&)>& f) const;
void reverseBreadthFirst(const std::function<void(const ChunkNode&)>& f) const;
const ChunkNode& find(const Geodetic2& location) const;
const ChunkNode& getChild(Quad quad) const;
@@ -84,7 +78,7 @@ public:
private:
ChunkNode* _parent;
std::unique_ptr<ChunkNode> _children[4];
std::array<std::unique_ptr<ChunkNode>, 4> _children;
Chunk _chunk;
};
@@ -92,4 +86,4 @@ private:
} // namespace globebrowsing
} // namespace openspace
#endif // __QUADTREE_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKNODE_H__

View File

@@ -1,157 +1,125 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/chunk/culling.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/chunk/chunk.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
#include <modules/globebrowsing/geometry/convexhull.h>
#include <modules/globebrowsing/meshes/trianglesoup.h>
#include <modules/debugging/rendering/debugrenderer.h>
namespace {
const std::string _loggerCat = "FrustrumCuller";
}
#include <modules/globebrowsing/globes/renderableglobe.h>
namespace openspace {
namespace globebrowsing {
//////////////////////////////////////////////////////////////////////////////////////
// FRUSTUM CULLER //
//////////////////////////////////////////////////////////////////////////////////////
FrustumCuller::FrustumCuller(const AABB3 viewFrustum)
: _viewFrustum(viewFrustum){
FrustumCuller::FrustumCuller(const AABB3 viewFrustum) : _viewFrustum(viewFrustum) {}
}
bool FrustumCuller::isCullable(const Chunk& chunk, const RenderData& data) {
// Calculate the MVP matrix
glm::dmat4 modelTransform = chunk.owner().modelTransform();
glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix());
glm::dmat4 modelViewProjectionTransform = glm::dmat4(data.camera.projectionMatrix())
* viewTransform * modelTransform;
FrustumCuller::~FrustumCuller() {
}
bool FrustumCuller::isCullable(const Chunk& chunk, const RenderData& data) {
// Calculate the MVP matrix
dmat4 modelTransform = chunk.owner().modelTransform();
dmat4 viewTransform = dmat4(data.camera.combinedViewMatrix());
dmat4 modelViewProjectionTransform = dmat4(data.camera.projectionMatrix())
* viewTransform * modelTransform;
const std::vector<glm::dvec4>& corners = chunk.getBoundingPolyhedronCorners();
const std::vector<glm::dvec4>& corners = chunk.getBoundingPolyhedronCorners();
// Create a bounding box that fits the patch corners
AABB3 bounds; // in screen space
std::vector<vec4> clippingSpaceCorners(8);
for (size_t i = 0; i < 8; i++) {
dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i];
clippingSpaceCorners[i] = cornerClippingSpace;
// Create a bounding box that fits the patch corners
AABB3 bounds; // in screen space
std::vector<glm::vec4> clippingSpaceCorners(8);
for (size_t i = 0; i < 8; i++) {
glm::dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i];
clippingSpaceCorners[i] = cornerClippingSpace;
dvec3 cornerNDC =
(1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace;
bounds.expand(cornerNDC);
glm::dvec3 cornerNDC =
(1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace;
bounds.expand(cornerNDC);
}
return !_viewFrustum.intersects(bounds);
}
bool HorizonCuller::isCullable(const Chunk& chunk, const RenderData& data) {
// Calculations are done in the reference frame of the globe. Hence, the camera
// position needs to be transformed with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
const GeodeticPatch& patch = chunk.surfacePatch();
float maxHeight = chunk.getBoundingHeights().max;
glm::dvec3 globePosition = glm::dvec3(0,0,0); // In model space it is 0
double minimumGlobeRadius = ellipsoid.minimumRadius();
glm::dvec3 cameraPosition =
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
glm::dvec3 globeToCamera = cameraPosition;
Geodetic2 cameraPositionOnGlobe =
ellipsoid.cartesianToGeodetic2(globeToCamera);
Geodetic2 closestPatchPoint = patch.closestPoint(cameraPositionOnGlobe);
glm::dvec3 objectPosition = ellipsoid.cartesianSurfacePosition(closestPatchPoint);
// objectPosition is closest in latlon space but not guaranteed to be closest in
// castesian coordinates. Therefore we compare it to the corners and pick the
// real closest point,
glm::dvec3 corners[4];
corners[0] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(NORTH_WEST));
corners[1] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(NORTH_EAST));
corners[2] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(SOUTH_WEST));
corners[3] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(SOUTH_EAST));
for (int i = 0; i < 4; ++i) {
float distance = glm::length(cameraPosition - corners[i]);
if (distance < glm::length(cameraPosition - objectPosition)) {
objectPosition = corners[i];
}
}
return !_viewFrustum.intersects(bounds);
}
return isCullable(cameraPosition, globePosition, objectPosition,
maxHeight, minimumGlobeRadius);
}
//////////////////////////////////////////////////////////////////////////////////////
// HORIZON CULLER //
//////////////////////////////////////////////////////////////////////////////////////
HorizonCuller::HorizonCuller() {
}
HorizonCuller::~HorizonCuller() {
}
bool HorizonCuller::isCullable(const Chunk& chunk, const RenderData& data) {
// Calculations are done in the reference frame of the globe. Hence, the camera
// position needs to be transformed with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
const GeodeticPatch& patch = chunk.surfacePatch();
float maxHeight = chunk.getBoundingHeights().max;
Vec3 globePosition = glm::dvec3(0,0,0); // In model space it is 0
Scalar minimumGlobeRadius = ellipsoid.minimumRadius();
Vec3 cameraPosition =
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
Vec3 globeToCamera = cameraPosition;
Geodetic2 cameraPositionOnGlobe =
ellipsoid.cartesianToGeodetic2(globeToCamera);
Geodetic2 closestPatchPoint = patch.closestPoint(cameraPositionOnGlobe);
Vec3 objectPosition = ellipsoid.cartesianSurfacePosition(closestPatchPoint);
// objectPosition is closest in latlon space but not guaranteed to be closest in
// castesian coordinates. Therefore we compare it to the corners and pick the
// real closest point,
glm::dvec3 corners[4];
corners[0] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(NORTH_WEST));
corners[1] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(NORTH_EAST));
corners[2] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(SOUTH_WEST));
corners[3] = ellipsoid.cartesianSurfacePosition(
chunk.surfacePatch().getCorner(SOUTH_EAST));
for (int i = 0; i < 4; ++i) {
float distance = glm::length(cameraPosition - corners[i]);
if (distance < glm::length(cameraPosition - objectPosition)) {
objectPosition = corners[i];
}
}
return isCullable(cameraPosition, globePosition, objectPosition,
maxHeight, minimumGlobeRadius);
}
bool HorizonCuller::isCullable(
const Vec3& cameraPosition,
const Vec3& globePosition,
const Vec3& objectPosition,
Scalar objectBoundingSphereRadius,
Scalar minimumGlobeRadius)
{
Scalar distanceToHorizon =
sqrt(pow(length(cameraPosition - globePosition), 2) -
pow(minimumGlobeRadius, 2));
Scalar minimumAllowedDistanceToObjectFromHorizon = sqrt(
pow(length(objectPosition - globePosition), 2) -
pow(minimumGlobeRadius - objectBoundingSphereRadius, 2));
// Minimum allowed for the object to be occluded
Scalar minimumAllowedDistanceToObjectSquared =
pow(distanceToHorizon + minimumAllowedDistanceToObjectFromHorizon, 2)
+ pow(objectBoundingSphereRadius, 2);
Scalar distanceToObjectSquared = pow(length(objectPosition - cameraPosition), 2);
return distanceToObjectSquared > minimumAllowedDistanceToObjectSquared;
}
bool HorizonCuller::isCullable(const glm::dvec3& cameraPosition,
const glm::dvec3& globePosition,
const glm::dvec3& objectPosition,
double objectBoundingSphereRadius,
double minimumGlobeRadius)
{
double distanceToHorizon =
sqrt(pow(length(cameraPosition - globePosition), 2) -
pow(minimumGlobeRadius, 2));
double minimumAllowedDistanceToObjectFromHorizon = sqrt(
pow(length(objectPosition - globePosition), 2) -
pow(minimumGlobeRadius - objectBoundingSphereRadius, 2));
// Minimum allowed for the object to be occluded
double minimumAllowedDistanceToObjectSquared =
pow(distanceToHorizon + minimumAllowedDistanceToObjectFromHorizon, 2)
+ pow(objectBoundingSphereRadius, 2);
double distanceToObjectSquared = pow(length(objectPosition - cameraPosition), 2);
return distanceToObjectSquared > minimumAllowedDistanceToObjectSquared;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,58 +1,49 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CULLING_H__
#define __CULLING_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CULLING_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CULLING_H__
#include <memory>
#include <glm/glm.hpp>
// open space includes
#include <openspace/rendering/renderable.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
#include <modules/globebrowsing/geometry/aabb.h>
namespace openspace {
struct RenderData;
namespace globebrowsing {
using namespace glm;
class Chunk;
class Chunk;
class ChunkCuller {
public:
virtual void update() { }
/**
* Determine if the Chunk is cullable. That is return true if removing the
* Chunk 'culling it' will not have any result on the final rendering. Culling
* it will make the rendering faster.
*/
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData) = 0;
};
class ChunkCuller {
public:
/**
* Determine if the Chunk is cullable. That is return true if removing the
* Chunk 'culling it' will not have any result on the final rendering. Culling
* it will make the rendering faster.
*/
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData) = 0;
};
/**
* Culls all chunks that are completely outside the view frustum.
@@ -61,41 +52,37 @@ namespace globebrowsing {
* screen space. This is calculated from a bounding polyhedron bounding the
* Chunk. Hence the culling will not be 'perfect' but fast and good enough for
* culling chunks outside the frustum with some margin.
*/
class FrustumCuller : public ChunkCuller {
public:
/**
* \param viewFrustum is the view space in normalized device coordinates space.
Hence it is an axis aligned bounding box and not a real frustum.
*/
FrustumCuller(const AABB3 viewFrustum);
~FrustumCuller();
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData);
private:
const AABB3 _viewFrustum;
};
*/
class FrustumCuller : public ChunkCuller {
public:
/**
* In this implementation of the horizon culling, the closer the ellipsoid is to a
* sphere, the better this will make the culling. Using the minimum radius to
* be safe. This means that if the ellipsoid has high difference between radii,
* splitting might accur even though it may not be needed.
*/
class HorizonCuller : public ChunkCuller {
public:
HorizonCuller();
~HorizonCuller();
* \param viewFrustum is the view space in normalized device coordinates space.
* Hence it is an axis aligned bounding box and not a real frustum.
*/
FrustumCuller(const AABB3 viewFrustum);
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData);
bool isCullable(const Chunk& chunk, const RenderData& renderData) override;
bool isCullable(const Vec3& cameraPosition, const Vec3& globePosition,
const Vec3& objectPosition, Scalar objectBoundingSphereRadius,
Scalar minimumGlobeRadius);
};
private:
const AABB3 _viewFrustum;
};
/**
* In this implementation of the horizon culling, the closer the ellipsoid is to a
* sphere, the better this will make the culling. Using the minimum radius to
* be safe. This means that if the ellipsoid has high difference between radii,
* splitting might accur even though it may not be needed.
*/
class HorizonCuller : public ChunkCuller {
public:
bool isCullable(const Chunk& chunk, const RenderData& renderData) override;
bool isCullable(const glm::dvec3& cameraPosition, const glm::dvec3& globePosition,
const glm::dvec3& objectPosition, double objectBoundingSphereRadius,
double minimumGlobeRadius);
};
} // namespace globebrowsing
} // namespace openspace
#endif // __CULLING_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CULLING_H__

View File

@@ -1,163 +1,189 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/aabb.h>
#include <string>
namespace {
const std::string _loggerCat = "AABB";
}
#include <limits>
namespace openspace {
namespace globebrowsing {
AABB1::AABB1() : min(1e35), max(-1e35) { }
AABB1::AABB1(float min, float max) : min(min), max(max) { }
AABB1::AABB1()
: AABB1(std::numeric_limits<float>::max(), -std::numeric_limits<float>::max())
{}
void AABB1::expand(float p) {
min = glm::min(min, p);
max = glm::max(max, p);
}
AABB1::AABB1(float min, float max)
: min(min)
, max(max)
{}
float AABB1::center() const {
return 0.5f * (min + max);
}
void AABB1::expand(float p) {
min = glm::min(min, p);
max = glm::max(max, p);
}
float AABB1::size() const {
return max - min;
}
float AABB1::center() const {
return 0.5f * (min + max);
}
bool AABB1::contains(float p) const {
return (min <= p) && (p <= max);
}
float AABB1::size() const {
return max - min;
}
bool AABB1::contains(const AABB1& o) const {
return (min <= o.min) && (o.max <= max);
}
bool AABB1::contains(float p) const {
return (min <= p) && (p <= max);
}
bool AABB1::intersects(const AABB1& o) const {
return (min <= o.max) && (o.min <= max);
}
bool AABB1::contains(const AABB1& o) const {
return (min <= o.min) && (o.max <= max);
}
AABBSpatialRelation AABB1::relationTo(const AABB1& o) const {
if (intersects(o)) {
if (contains(o)) return AABBSpatialRelation::Containing;
if (o.contains(*this)) return AABBSpatialRelation::Contained;
return AABBSpatialRelation::Intersecting;
bool AABB1::intersects(const AABB1& o) const {
return (min <= o.max) && (o.min <= max);
}
AABBSpatialRelation AABB1::relationTo(const AABB1& o) const {
if (intersects(o)) {
if (contains(o)) {
return AABBSpatialRelation::Containing;
}
return AABBSpatialRelation::None;
}
AABB2::AABB2() : min(1e35), max(-1e35) { }
AABB2::AABB2(const vec2& min, const vec2& max) : min(min), max(max) { }
void AABB2::expand(const vec2& p) {
min.x = glm::min(min.x, p.x);
min.y = glm::min(min.y, p.y);
max.x = glm::max(max.x, p.x);
max.y = glm::max(max.y, p.y);
}
vec2 AABB2::center() const {
return 0.5f * (min + max);
}
vec2 AABB2::size() const {
return max - min;
}
bool AABB2::contains(const vec2& p) const {
return (min.x <= p.x) && (p.x <= max.x)
&& (min.y <= p.y) && (p.y <= max.y);
}
bool AABB2::contains(const AABB2& o) const {
return (min.x <= o.min.x) && (o.max.x <= max.x)
&& (min.y <= o.min.y) && (o.max.y <= max.y);
}
bool AABB2::intersects(const AABB2& o) const {
return (min.x <= o.max.x) && (o.min.x <= max.x)
&& (min.y <= o.max.y) && (o.min.y <= max.y);
}
AABBSpatialRelation AABB2::relationTo(const AABB2& o) const {
if (intersects(o)) {
if (contains(o)) return AABBSpatialRelation::Containing;
if (o.contains(*this)) return AABBSpatialRelation::Contained;
return AABBSpatialRelation::Intersecting;
if (o.contains(*this)) {
return AABBSpatialRelation::Contained;
}
return AABBSpatialRelation::None;
return AABBSpatialRelation::Intersecting;
}
return AABBSpatialRelation::None;
}
AABB3::AABB3() : min(1e35), max(-1e35) { }
AABB3::AABB3(const vec3& min, const vec3& max) : min(min), max(max) { }
AABB2::AABB2()
: AABB2(
glm::vec2(std::numeric_limits<float>::max()),
glm::vec2(-std::numeric_limits<float>::max())
)
{}
void AABB3::expand(const vec3 p) {
min.x = glm::min(min.x, p.x);
min.y = glm::min(min.y, p.y);
min.z = glm::min(min.z, p.z);
max.x = glm::max(max.x, p.x);
max.y = glm::max(max.y, p.y);
max.z = glm::max(max.z, p.z);
}
AABB2::AABB2(const glm::vec2& min, const glm::vec2& max)
: min(min)
, max(max)
{}
vec3 AABB3::center() const {
return 0.5f * (min + max);
}
void AABB2::expand(const glm::vec2& p) {
min = glm::min(min, p);
max = glm::max(max, p);
}
vec3 AABB3::size() const {
return max - min;
}
glm::vec2 AABB2::center() const {
return 0.5f * (min + max);
}
bool AABB3::contains(const vec3& p) const {
return (min.x <= p.x) && (p.x <= max.x)
&& (min.y <= p.y) && (p.y <= max.y)
&& (min.z <= p.z) && (p.z <= max.z);
}
glm::vec2 AABB2::size() const {
return max - min;
}
bool AABB3::contains(const AABB3& o) const {
return (min.x <= o.min.x) && (o.max.x <= max.x)
&& (min.y <= o.min.y) && (o.max.y <= max.y)
&& (min.z <= o.min.z) && (o.max.z <= max.z);
}
bool AABB2::contains(const glm::vec2& p) const {
return (min.x <= p.x) && (p.x <= max.x)
&& (min.y <= p.y) && (p.y <= max.y);
}
bool AABB3::intersects(const AABB3& o) const {
return (min.x <= o.max.x) && (o.min.x <= max.x)
&& (min.y <= o.max.y) && (o.min.y <= max.y)
&& (min.z <= o.max.z) && (o.min.z <= max.z);
}
bool AABB2::contains(const AABB2& o) const {
return (min.x <= o.min.x) && (o.max.x <= max.x)
&& (min.y <= o.min.y) && (o.max.y <= max.y);
}
AABBSpatialRelation AABB3::relationTo(const AABB3& o) const {
if (intersects(o)) {
if (contains(o)) return AABBSpatialRelation::Containing;
if (o.contains(*this)) return AABBSpatialRelation::Contained;
return AABBSpatialRelation::Intersecting;
bool AABB2::intersects(const AABB2& o) const {
return (min.x <= o.max.x) && (o.min.x <= max.x)
&& (min.y <= o.max.y) && (o.min.y <= max.y);
}
AABBSpatialRelation AABB2::relationTo(const AABB2& o) const {
if (intersects(o)) {
if (contains(o)) {
return AABBSpatialRelation::Containing;
}
return AABBSpatialRelation::None;
if (o.contains(*this)) {
return AABBSpatialRelation::Contained;
}
return AABBSpatialRelation::Intersecting;
}
return AABBSpatialRelation::None;
}
AABB3::AABB3()
: AABB3(
glm::vec3(std::numeric_limits<float>::max()),
glm::vec3(-std::numeric_limits<float>::max())
)
{}
AABB3::AABB3(const glm::vec3& min, const glm::vec3& max)
: min(min),
max(max)
{}
void AABB3::expand(const glm::vec3 p) {
min = glm::min(min, p);
max = glm::max(max, p);
}
glm::vec3 AABB3::center() const {
return 0.5f * (min + max);
}
glm::vec3 AABB3::size() const {
return max - min;
}
bool AABB3::contains(const glm::vec3& p) const {
return (min.x <= p.x) && (p.x <= max.x)
&& (min.y <= p.y) && (p.y <= max.y)
&& (min.z <= p.z) && (p.z <= max.z);
}
bool AABB3::contains(const AABB3& o) const {
return (min.x <= o.min.x) && (o.max.x <= max.x)
&& (min.y <= o.min.y) && (o.max.y <= max.y)
&& (min.z <= o.min.z) && (o.max.z <= max.z);
}
bool AABB3::intersects(const AABB3& o) const {
return (min.x <= o.max.x) && (o.min.x <= max.x)
&& (min.y <= o.max.y) && (o.min.y <= max.y)
&& (min.z <= o.max.z) && (o.min.z <= max.z);
}
AABBSpatialRelation AABB3::relationTo(const AABB3& o) const {
if (intersects(o)) {
if (contains(o)) {
return AABBSpatialRelation::Containing;
}
if (o.contains(*this)) {
return AABBSpatialRelation::Contained;
}
return AABBSpatialRelation::Intersecting;
}
return AABBSpatialRelation::None;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,94 +1,91 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __AABB_H__
#define __AABB_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_AABB_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_AABB_H__
#include <memory>
#include <glm/glm.hpp>
namespace openspace {
namespace globebrowsing {
using namespace glm;
enum class AABBSpatialRelation {
None,
Intersecting,
Contained,
Containing
};
enum class AABBSpatialRelation {
None,
Intersecting,
Contained,
Containing
};
struct AABB1 {
AABB1();
AABB1(float min, float max);
struct AABB1 {
AABB1();
AABB1(float min, float max);
void expand(float p);
float center() const;
float size() const;
bool contains(float p) const;
bool contains(const AABB1& o) const;
bool intersects(const AABB1& o) const;
AABBSpatialRelation relationTo(const AABB1& o) const;
void expand(float p);
float center() const;
float size() const;
bool contains(float p) const;
bool contains(const AABB1& o) const;
bool intersects(const AABB1& o) const;
AABBSpatialRelation relationTo(const AABB1& o) const;
float min;
float max;
};
float min;
float max;
};
struct AABB2 {
AABB2();
AABB2(const glm::vec2& min, const glm::vec2& max);
struct AABB2 {
AABB2();
AABB2(const vec2& min, const vec2& max);
void expand(const glm::vec2& p);
glm::vec2 center() const;
glm::vec2 size() const;
bool contains(const glm::vec2& p) const;
bool contains(const AABB2& o) const;
bool intersects(const AABB2& o) const;
AABBSpatialRelation relationTo(const AABB2& o) const;
void expand(const vec2& p);
vec2 center() const;
vec2 size() const;
bool contains(const vec2& p) const;
bool contains(const AABB2& o) const;
bool intersects(const AABB2& o) const;
AABBSpatialRelation relationTo(const AABB2& o) const;
glm::vec2 min;
glm::vec2 max;
};
vec2 min;
vec2 max;
};
struct AABB3 {
AABB3();
AABB3(const glm::vec3& min, const glm::vec3& max);
struct AABB3 {
AABB3();
AABB3(const vec3& min, const vec3& max);
void expand(const glm::vec3 p);
glm::vec3 center() const;
glm::vec3 size() const;
bool contains(const glm::vec3& p) const;
bool contains(const AABB3& o) const;
bool intersects(const AABB3& o) const;
AABBSpatialRelation relationTo(const AABB3& o) const;
void expand(const vec3 p);
vec3 center() const;
vec3 size() const;
bool contains(const vec3& p) const;
bool contains(const AABB3& o) const;
bool intersects(const AABB3& o) const;
AABBSpatialRelation relationTo(const AABB3& o) const;
vec3 min;
vec3 max;
};
glm::vec3 min;
glm::vec3 max;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __AABB_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_AABB_H__

View File

@@ -1,178 +1,170 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/convexhull.h>
#include <string>
#include <stack>
#include <algorithm>
#include <functional>
namespace {
const std::string _loggerCat = "ConvexHull";
}
namespace openspace {
namespace globebrowsing {
Point2 ConvexHull2::p0(0,0);
glm::vec2 ConvexHull2::p0(0,0);
ConvexHull2::ConvexHull2(){ }
ConvexHull2 ConvexHull2::grahamScan_NOT_THREAD_SAFE(std::vector<glm::vec2>& points,
int yMinIndex)
{
ConvexHull2 hull;
ConvexHull2 ConvexHull2::grahamScan_NOT_THREAD_SAFE(std::vector<Point2>& points, int yMinIndex){
ConvexHull2 hull;
if (yMinIndex == -1){
yMinIndex = 0;
float ymin = points[0].y;
for (int i = 1; i < points.size(); i++) {
float y = points[i].y;
// Pick the bottom-most or chose the left most point in case of tie
if ((y < ymin) || (ymin == y && points[i].x < points[yMinIndex].x)) {
ymin = points[i].y;
yMinIndex = i;
}
if (yMinIndex == -1) {
yMinIndex = 0;
float ymin = points[0].y;
for (int i = 1; i < points.size(); i++) {
float y = points[i].y;
// Pick the bottom-most or chose the left most point in case of tie
if ((y < ymin) || (ymin == y && points[i].x < points[yMinIndex].x)) {
ymin = points[i].y;
yMinIndex = i;
}
}
}
// Place the bottom-most point at first position
swap(points[0], points[yMinIndex]);
// Place the bottom-most point at first position
swap(points[0], points[yMinIndex]);
// Sort n-1 points with respect to the first point. A point p1 comes
// before p2 in sorted ouput if p2 has larger polar angle (in
// counterclockwise direction) than p1
hull.p0 = points[0];
// Sort n-1 points with respect to the first point. A point p1 comes
// before p2 in sorted ouput if p2 has larger polar angle (in
// counterclockwise direction) than p1
hull.p0 = points[0];
qsort(&(points.data()[1]), points.size()-1, sizeof(Point2), &(hull.compare));
// Replace with std::sort
qsort(&(points.data()[1]), points.size()-1, sizeof(glm::vec2), &(hull.compare));
// Create an empty stack and push first three points to it.
std::stack<glm::vec2> S;
S.push(points[0]);
S.push(points[1]);
S.push(points[2]);
// Create an empty stack and push first three points to it.
std::stack<Point2> S;
S.push(points[0]);
S.push(points[1]);
S.push(points[2]);
// Process remaining n-3 points
for (int i = 3; i < points.size(); i++)
{
// Keep removing top while the angle formed by points next-to-top,
// top, and points[i] makes a non-left turn
while (orientation(oneBelowTop(S), S.top(), points[i]) == 1)
S.pop();
S.push(points[i]);
}
// Now stack has the output points, print contents of stack
while (!S.empty())
{
Point2 p = S.top();
hull._points.push_back(p);
// Process remaining n-3 points
for (int i = 3; i < points.size(); i++) {
// Keep removing top while the angle formed by points next-to-top,
// top, and points[i] makes a non-left turn
while (orientation(oneBelowTop(S), S.top(), points[i]) == 1)
S.pop();
}
return hull;
S.push(points[i]);
}
bool ConvexHull2::intersects(const ConvexHull2& other) const {
// uses Separating Axis Theorem
// ref: http://stackoverflow.com/questions/753140/how-do-i-determine-if-two-convex-polygons-intersect
return this->hasPerpendicularLineWhereProjectedPointsOverlap(other) ||
other.hasPerpendicularLineWhereProjectedPointsOverlap(*this);
// Now stack has the output points, print contents of stack
while (!S.empty()) {
glm::vec2 p = S.top();
hull._points.push_back(p);
S.pop();
}
return hull;
}
bool ConvexHull2::hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const {
for (size_t i = 1; i < _points.size(); i++) {
glm::vec2 dividingAxis = _points[i] - _points[i - 1];
// project all points onto the vector perpendicular to the dividing axis
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
const AABB1& myBounds = projectedRegion(projAxis);
const AABB1& otherBounds = other.projectedRegion(projAxis);
if (!myBounds.intersects(otherBounds)) {
return false;
}
}
bool ConvexHull2::intersects(const ConvexHull2& other) const {
// uses Separating Axis Theorem
// ref: http://stackoverflow.com/questions/753140/how-do-i-determine-if-two-convex-polygons-intersect
return this->hasPerpendicularLineWhereProjectedPointsOverlap(other) ||
other.hasPerpendicularLineWhereProjectedPointsOverlap(*this);
}
// test line defined by last-to-first point
glm::vec2 dividingAxis = _points[0] - _points.back();
bool ConvexHull2::hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const {
for (size_t i = 1; i < _points.size(); i++) {
glm::vec2 dividingAxis = _points[i] - _points[i - 1];
// project all points onto the vector perpendicular to the dividing axis
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
const AABB1& myBounds = projectedRegion(projAxis);
const AABB1& otherBounds = other.projectedRegion(projAxis);
if (!myBounds.intersects(otherBounds)) {
return false;
}
return true;
}
AABB1 ConvexHull2::projectedRegion(glm::vec2 direction) const {
AABB1 projectedRegion;
for (size_t i = 0; i < _points.size(); i++) {
projectedRegion.expand(glm::dot(_points[i], direction));
}
return projectedRegion;
// test line defined by last-to-first point
glm::vec2 dividingAxis = _points[0] - _points.back();
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
const AABB1& myBounds = projectedRegion(projAxis);
const AABB1& otherBounds = other.projectedRegion(projAxis);
if (!myBounds.intersects(otherBounds)) {
return false;
}
Point2 ConvexHull2::oneBelowTop(std::stack<Point2>& S) {
Point2 p = S.top();
S.pop();
Point2 res = S.top();
S.push(p);
return res;
return true;
}
AABB1 ConvexHull2::projectedRegion(glm::vec2 direction) const {
AABB1 projectedRegion;
for (const glm::vec2& p : _points) {
projectedRegion.expand(glm::dot(p, direction));
}
//for (size_t i = 0; i < _points.size(); i++) {
// projectedRegion.expand(glm::dot(_points[i], direction));
//}
return projectedRegion;
}
glm::vec2 ConvexHull2::oneBelowTop(std::stack<glm::vec2>& S) {
glm::vec2 p = S.top();
S.pop();
glm::vec2 res = S.top();
S.push(p);
return res;
}
void ConvexHull2::swap(glm::vec2& p1, glm::vec2& p2) {
glm::vec2 temp = p1;
p1 = p2;
p2 = temp;
}
const std::vector<glm::vec2> ConvexHull2::points() const {
return _points;
}
int ConvexHull2::orientation(const glm::vec2& p, const glm::vec2& q, const glm::vec2& r) {
float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
return (val == 0) ? 0 : (val > 0) ? 1 : 2;
}
float ConvexHull2::dist(const glm::vec2& p1, const glm::vec2& p2) {
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
int ConvexHull2::compare(const void *vp1, const void *vp2) {
glm::vec2* p1 = (glm::vec2 *)vp1;
glm::vec2* p2 = (glm::vec2 *)vp2;
// Find orientation
int o = orientation(p0, *p1, *p2);
if (o == 0) {
return (dist(p0, *p2) >= dist(p0, *p1)) ? -1 : 1;
}
void ConvexHull2::swap(Point2& p1, Point2& p2) {
Point2 temp = p1;
p1 = p2;
p2 = temp;
}
return (o == 2) ? -1 : 1;
}
const std::vector<Point2> ConvexHull2::points() const {
return _points;
}
int ConvexHull2::orientation(const Point2& p, const Point2& q, const Point2& r) {
float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
return (val == 0) ? 0 : (val > 0) ? 1 : 2;
}
float ConvexHull2::dist(const Point2& p1, const Point2& p2) {
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
int ConvexHull2::compare(const void *vp1, const void *vp2) {
Point2 *p1 = (Point2 *)vp1;
Point2 *p2 = (Point2 *)vp2;
// Find orientation
int o = orientation(p0, *p1, *p2);
if (o == 0)
return (dist(p0, *p2) >= dist(p0, *p1)) ? -1 : 1;
return (o == 2) ? -1 : 1;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,78 +1,72 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CONVEX_HULL_H__
#define __CONVEX_HULL_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CONVEX_HULL_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CONVEX_HULL_H__
#include <modules/globebrowsing/geometry/aabb.h>
#include <vector>
#include <stack>
#include <vector>
#include <memory>
#include <glm/glm.hpp>
namespace openspace {
namespace globebrowsing {
using namespace glm;
// Implementation based on
// http://www.sanfoundry.com/cpp-program-implement-graham-scan-algorithm-find-convex-hull/
class ConvexHull2 {
public:
static ConvexHull2 grahamScan_NOT_THREAD_SAFE(std::vector<glm::vec2>& points,
int yMinIndex = -1);
const std::vector<glm::vec2> points() const;
bool intersects(const ConvexHull2& o) const;
AABB1 projectedRegion(glm::vec2 direction) const;
// Implementation based on
// http://www.sanfoundry.com/cpp-program-implement-graham-scan-algorithm-find-convex-hull/
private:
bool hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const;
typedef glm::vec2 Point2;
static int compare(const void* vp1, const void* vp2);
class ConvexHull2 {
public:
ConvexHull2();
static glm::vec2 oneBelowTop(std::stack<glm::vec2>&);
static void swap(glm::vec2& p1, glm::vec2& p2);
static ConvexHull2 grahamScan_NOT_THREAD_SAFE(std::vector<Point2>& points, int yMinIndex = -1);
// returns 0 = colinear, 1 = clockwise, 2 = counterclockwise
static int orientation(const glm::vec2& p, const glm::vec2& q, const glm::vec2& r);
static float dist(const glm::vec2& p1, const glm::vec2& p2);
const std::vector<Point2> points() const;
bool intersects(const ConvexHull2& o) const;
AABB1 projectedRegion(glm::vec2 direction) const;
private:
bool hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const;
static int compare(const void *vp1, const void *vp2);
static Point2 oneBelowTop(std::stack<Point2>&);
static void swap(Point2& p1, Point2& p2);
// returns 0 = colinear, 1 = clockwise, 2 = counterclockwise
static int orientation(const Point2& p, const Point2& q, const Point2& r);
static float dist(const Point2& p1, const Point2& p2);
private:
static Point2 p0;
std::vector<Point2> _points;
};
private:
static glm::vec2 p0;
std::vector<glm::vec2> _points;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __CONVEX_HULL_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CONVEX_HULL_H__

View File

@@ -24,167 +24,150 @@
#include <modules/globebrowsing/geometry/ellipsoid.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <algorithm>
namespace {
const std::string _loggerCat = "Ellipsoid";
}
#include <vector>
namespace openspace {
namespace globebrowsing {
Ellipsoid::Ellipsoid() : Ellipsoid(1,1,1) {
Ellipsoid::Ellipsoid(glm::dvec3 radii) : _radii(radii) {
updateInternalCache();
}
}
void Ellipsoid::updateInternalCache() {
_cached._radiiSquared = glm::dvec3(
(_radii.x * _radii.x),
(_radii.y * _radii.y),
(_radii.z * _radii.z));
Ellipsoid::Ellipsoid(Vec3 radii) : _radii(radii) {
updateInternalCache();
}
Ellipsoid::Ellipsoid(Scalar x, Scalar y, Scalar z) : _radii(x, y, z) {
updateInternalCache();
}
Ellipsoid::~Ellipsoid(){
}
void Ellipsoid::updateInternalCache() {
_cached._radiiSquared = Vec3(
(_radii.x * _radii.x),
(_radii.y * _radii.y),
(_radii.z * _radii.z));
_cached._oneOverRadiiSquared = Vec3(1) / _cached._radiiSquared;
_cached._radiiToTheFourth = _cached._radiiSquared * _cached._radiiSquared;
_cached._oneOverRadiiSquared = glm::dvec3(1) / _cached._radiiSquared;
_cached._radiiToTheFourth = _cached._radiiSquared * _cached._radiiSquared;
std::vector<Scalar> radii = { _radii.x, _radii.y, _radii.z };
std::sort(radii.begin(), radii.end());
_cached._minimumRadius = radii[0];
_cached._medianRadius = radii[1];
_cached._maximumRadius = radii[2];
}
std::vector<double> radii = { _radii.x, _radii.y, _radii.z };
std::sort(radii.begin(), radii.end());
_cached._minimumRadius = radii[0];
_cached._medianRadius = radii[1];
_cached._maximumRadius = radii[2];
}
Vec3 Ellipsoid::geocentricSurfaceProjection(const Vec3& p) const {
Scalar beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
return beta * p;
}
glm::dvec3 Ellipsoid::geocentricSurfaceProjection(const glm::dvec3& p) const {
double beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
return beta * p;
}
Vec3 Ellipsoid::geodeticSurfaceProjection(const Vec3& p) const {
Scalar beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
Scalar n = glm::length(beta * p * _cached._oneOverRadiiSquared);
Scalar alpha = (1.0 - beta) * (glm::length(p) / n);
glm::dvec3 Ellipsoid::geodeticSurfaceProjection(const glm::dvec3& p) const {
double beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
double n = glm::length(beta * p * _cached._oneOverRadiiSquared);
double alpha = (1.0 - beta) * (glm::length(p) / n);
Vec3 p2 = p * p;
Vec3 d, d2, d3;
glm::dvec3 p2 = p * p;
glm::dvec3 d, d2, d3;
Scalar s = 0.0;
Scalar dSdA = 1.0;
double s = 0.0;
double dSdA = 1.0;
Scalar epsilon = 1e-10;
do {
alpha -= (s / dSdA);
double epsilon = 1e-10;
do {
alpha -= (s / dSdA);
d = Vec3(1.0) + alpha * _cached._oneOverRadiiSquared;
d2 = d * d;
d3 = d * d2;
d = glm::dvec3(1.0) + alpha * _cached._oneOverRadiiSquared;
d2 = d * d;
d3 = d * d2;
s = glm::dot(p2 / (_cached._radiiSquared * d2), Vec3(1.0)) - 1.0;
s = glm::dot(p2 / (_cached._radiiSquared * d2), glm::dvec3(1.0)) - 1.0;
dSdA = -2.0 * glm::dot(p2 / (_cached._radiiToTheFourth * d3), Vec3(1.0));
}
while (abs(s) > epsilon);
return p / d;
dSdA = -2.0 * glm::dot(p2 / (_cached._radiiToTheFourth * d3), glm::dvec3(1.0));
}
while (abs(s) > epsilon);
return p / d;
}
Vec3 Ellipsoid::geodeticSurfaceNormalForGeocentricallyProjectedPoint(const Vec3& p) const {
Vec3 normal = p * _cached._oneOverRadiiSquared;
return glm::normalize(normal);
}
glm::dvec3 Ellipsoid::geodeticSurfaceNormalForGeocentricallyProjectedPoint(const glm::dvec3& p) const {
glm::dvec3 normal = p * _cached._oneOverRadiiSquared;
return glm::normalize(normal);
}
Vec3 Ellipsoid::geodeticSurfaceNormal(Geodetic2 geodetic2) const {
Scalar cosLat = glm::cos(geodetic2.lat);
//geodetic2.lon = geodetic2.lon > M_PI ? geodetic2.lon - M_PI * 2 : geodetic2.lon;
return Vec3(
cosLat * cos(geodetic2.lon),
cosLat * sin(geodetic2.lon),
sin(geodetic2.lat));
}
glm::dvec3 Ellipsoid::geodeticSurfaceNormal(Geodetic2 geodetic2) const {
double cosLat = glm::cos(geodetic2.lat);
//geodetic2.lon = geodetic2.lon > M_PI ? geodetic2.lon - M_PI * 2 : geodetic2.lon;
return glm::dvec3(
cosLat * cos(geodetic2.lon),
cosLat * sin(geodetic2.lon),
sin(geodetic2.lat));
}
const Vec3& Ellipsoid::radii() const {
return _radii;
}
const glm::dvec3& Ellipsoid::radii() const {
return _radii;
}
const Vec3& Ellipsoid::radiiSquared() const {
return _cached._radiiSquared;
}
const glm::dvec3& Ellipsoid::radiiSquared() const {
return _cached._radiiSquared;
}
const Vec3& Ellipsoid::oneOverRadiiSquared() const {
return _cached._oneOverRadiiSquared;
}
const glm::dvec3& Ellipsoid::oneOverRadiiSquared() const {
return _cached._oneOverRadiiSquared;
}
const Vec3& Ellipsoid::radiiToTheFourth() const {
return _cached._radiiToTheFourth;
}
const glm::dvec3& Ellipsoid::radiiToTheFourth() const {
return _cached._radiiToTheFourth;
}
Scalar Ellipsoid::minimumRadius() const {
return _cached._minimumRadius;
}
double Ellipsoid::minimumRadius() const {
return _cached._minimumRadius;
}
Scalar Ellipsoid::maximumRadius() const {
return _cached._maximumRadius;
}
double Ellipsoid::maximumRadius() const {
return _cached._maximumRadius;
}
Scalar Ellipsoid::averageRadius() const {
return (_radii.x + _radii.y + _radii.z) / 3.0;
}
double Ellipsoid::averageRadius() const {
return (_radii.x + _radii.y + _radii.z) / 3.0;
}
Scalar Ellipsoid::longitudalDistance(Scalar lat, Scalar lon1, Scalar lon2) const {
Vec2 ellipseRadii = glm::cos(lat) * Vec2(_radii);
// Approximating with the ellipse mean radius
Scalar meanRadius = 0.5 * (ellipseRadii.x + ellipseRadii.y);
return meanRadius * std::abs(lon2 - lon1);
}
double Ellipsoid::longitudalDistance(double lat, double lon1, double lon2) const {
glm::dvec2 ellipseRadii = glm::cos(lat) * glm::dvec2(_radii);
// Approximating with the ellipse mean radius
double meanRadius = 0.5 * (ellipseRadii.x + ellipseRadii.y);
return meanRadius * std::abs(lon2 - lon1);
}
Scalar Ellipsoid::greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const{
// https://en.wikipedia.org/wiki/Meridian_arc
// https://en.wikipedia.org/wiki/Great-circle_distance#Vector_version
double Ellipsoid::greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const{
// https://en.wikipedia.org/wiki/Meridian_arc
// https://en.wikipedia.org/wiki/Great-circle_distance#Vector_version
Vec3 n1 = geodeticSurfaceNormal(p1);
Vec3 n2 = geodeticSurfaceNormal(p2);
Scalar centralAngle = glm::atan(glm::length(glm::cross(n1, n2)) / glm::dot(n1, n2));
glm::dvec3 n1 = geodeticSurfaceNormal(p1);
glm::dvec3 n2 = geodeticSurfaceNormal(p2);
double centralAngle = glm::atan(glm::length(glm::cross(n1, n2)) / glm::dot(n1, n2));
Geodetic2 pMid = (p1 + p2) / 2;
Vec3 centralNormal = cartesianSurfacePosition(pMid);
Geodetic2 pMid = (p1 + p2) / 2;
glm::dvec3 centralNormal = cartesianSurfacePosition(pMid);
return centralAngle * glm::length(centralNormal);
}
return centralAngle * glm::length(centralNormal);
}
Geodetic2 Ellipsoid::cartesianToGeodetic2(const Vec3& p) const
{
Vec3 normal = geodeticSurfaceNormalForGeocentricallyProjectedPoint(p);
return Geodetic2(
asin(normal.z / length(normal)), // Latitude
atan2(normal.y, normal.x)); // Longitude
}
Geodetic2 Ellipsoid::cartesianToGeodetic2(const glm::dvec3& p) const
{
glm::dvec3 normal = geodeticSurfaceNormalForGeocentricallyProjectedPoint(p);
return Geodetic2(
asin(normal.z / length(normal)), // Latitude
atan2(normal.y, normal.x)); // Longitude
}
Vec3 Ellipsoid::cartesianSurfacePosition(const Geodetic2& geodetic2) const
{
// Position on surface : height = 0
return cartesianPosition(Geodetic3({ geodetic2, 0 }));
}
glm::dvec3 Ellipsoid::cartesianSurfacePosition(const Geodetic2& geodetic2) const
{
// Position on surface : height = 0
return cartesianPosition(Geodetic3({ geodetic2, 0 }));
}
Vec3 Ellipsoid::cartesianPosition(const Geodetic3& geodetic3) const
{
Vec3 normal = geodeticSurfaceNormal(geodetic3.geodetic2);
Vec3 k = _cached._radiiSquared * normal;
Scalar gamma = sqrt(dot(k, normal));
Vec3 rSurface = k / gamma;
return rSurface + geodetic3.height * normal;
}
glm::dvec3 Ellipsoid::cartesianPosition(const Geodetic3& geodetic3) const
{
glm::dvec3 normal = geodeticSurfaceNormal(geodetic3.geodetic2);
glm::dvec3 k = _cached._radiiSquared * normal;
double gamma = sqrt(dot(k, normal));
glm::dvec3 rSurface = k / gamma;
return rSurface + geodetic3.height * normal;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -22,92 +22,83 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __ELLIPSOID_H__
#define __ELLIPSOID_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_ELLIPSOID_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_ELLIPSOID_H__
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <ghoul/glm.h>
namespace openspace {
namespace globebrowsing {
/**
This class is based largely on the Ellipsoid class defined in the book
"3D Engine Design for Virtual Globes". Most planets or planetary objects are better
described using ellipsoids than spheres. All inputs and outputs to this class is
based on the WGS84 standard coordinate system where the x-axis points towards geographic
(lat = 0, lon = 0), the y-axis points towards (lat = 0, lon = 90deg) and the
z-axis points towards the north pole. For other globes than earth of course the radii
can differ.
*/
/**
* This class is based largely on the Ellipsoid class defined in the book
* "3D Engine Design for Virtual Globes". Most planets or planetary objects are better
* described using ellipsoids than spheres. All inputs and outputs to this class is
* based on the WGS84 standard coordinate system where the x-axis points towards geographic
* (lat = 0, lon = 0), the y-axis points towards (lat = 0, lon = 90deg) and the
* z-axis points towards the north pole. For other globes than earth of course the radii
* can differ.
*/
class Ellipsoid {
public:
Ellipsoid();
/**
* \param radii defines three radii for the Ellipsoid
*/
Ellipsoid(glm::dvec3 radii = glm::dvec3(1.0, 1.0, 1.0));
/**
\param radii defines three radii for the Ellipsoid
*/
Ellipsoid(Vec3 radii);
* Scales a point along the geocentric normal and places it on the surface of the
* Ellipsoid.
* \param p is a point in the cartesian coordinate system to be placed on the surface
* of the Ellipsoid
*/
glm::dvec3 geocentricSurfaceProjection(const glm::dvec3& p) const;
/**
\param x defines the radius in x direction.
\param y defines the radius in y direction.
\param z defines the radius in z direction.
*/
Ellipsoid(Scalar x, Scalar y, Scalar z);
~Ellipsoid();
* Scales a point along the geodetic normal and places it on the surface of the
* Ellipsoid.
* \param p is a point in the cartesian coordinate system to be placed on the surface
* of the Ellipsoid
*/
glm::dvec3 geodeticSurfaceProjection(const glm::dvec3& p) const;
/**
Scales a point along the geocentric normal and places it on the surface of the
Ellipsoid.
\param p is a point in the cartesian coordinate system to be placed on the surface
of the Ellipsoid
*/
Vec3 geocentricSurfaceProjection(const Vec3& p) const;
/**
Scales a point along the geodetic normal and places it on the surface of the
Ellipsoid.
\param p is a point in the cartesian coordinate system to be placed on the surface
of the Ellipsoid
*/
Vec3 geodeticSurfaceProjection(const Vec3& p) const;
Vec3 geodeticSurfaceNormalForGeocentricallyProjectedPoint(const Vec3& p) const;
Vec3 geodeticSurfaceNormal(Geodetic2 geodetic2) const;
glm::dvec3 geodeticSurfaceNormalForGeocentricallyProjectedPoint(const glm::dvec3& p) const;
glm::dvec3 geodeticSurfaceNormal(Geodetic2 geodetic2) const;
const Vec3& radii() const;
const Vec3& radiiSquared() const;
const Vec3& oneOverRadiiSquared() const;
const Vec3& radiiToTheFourth() const;
const glm::dvec3& radii() const;
const glm::dvec3& radiiSquared() const;
const glm::dvec3& oneOverRadiiSquared() const;
const glm::dvec3& radiiToTheFourth() const;
Scalar minimumRadius() const;
Scalar maximumRadius() const;
Scalar averageRadius() const;
double minimumRadius() const;
double maximumRadius() const;
double averageRadius() const;
Scalar longitudalDistance(Scalar lat, Scalar lon1, Scalar lon2) const;
Scalar greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const;
double longitudalDistance(double lat, double lon1, double lon2) const;
double greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const;
Geodetic2 cartesianToGeodetic2(const Vec3& p) const;
Vec3 cartesianSurfacePosition(const Geodetic2& geodetic2) const;
Vec3 cartesianPosition(const Geodetic3& geodetic3) const;
Geodetic2 cartesianToGeodetic2(const glm::dvec3& p) const;
glm::dvec3 cartesianSurfacePosition(const Geodetic2& geodetic2) const;
glm::dvec3 cartesianPosition(const Geodetic3& geodetic3) const;
private:
struct EllipsoidCache {
Vec3 _radiiSquared;
Vec3 _oneOverRadiiSquared;
Vec3 _radiiToTheFourth;
Scalar _minimumRadius;
Scalar _maximumRadius;
Scalar _medianRadius;
glm::dvec3 _radiiSquared;
glm::dvec3 _oneOverRadiiSquared;
glm::dvec3 _radiiToTheFourth;
double _minimumRadius;
double _maximumRadius;
double _medianRadius;
} _cached;
void updateInternalCache();
Vec3 _radii;
glm::dvec3 _radii;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __ELLIPSOID_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_ELLIPSOID_H__

View File

@@ -23,277 +23,252 @@
****************************************************************************************/
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/geometry/angle.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
#include <ghoul/misc/assert.h>
namespace {
const std::string _loggerCat = "Geodetic2";
}
namespace openspace {
namespace globebrowsing {
//////////////////////////////////////////////////////////////////////////////////////
// GEODETIC2 //
//////////////////////////////////////////////////////////////////////////////////////
Geodetic2::Geodetic2(double latitude, double longitude)
: lat(latitude)
, lon(longitude)
{}
Geodetic2::Geodetic2()
: lat(0)
, lon(0)
{}
Geodetic2::Geodetic2(const Geodetic2& p)
: Geodetic2(p.lat, p.lon)
{}
Geodetic2::Geodetic2(Scalar latitude, Scalar longitude)
: lat(latitude)
, lon(longitude)
{}
glm::dvec2 Geodetic2::toLonLatVec2() const {
return glm::dvec2(lon, lat);
}
Geodetic2::Geodetic2(const Geodetic2& p)
: Geodetic2(p.lat, p.lon)
{}
bool Geodetic2::operator==(const Geodetic2& other) const {
return lat == other.lat && lon == other.lon;
}
Vec2 Geodetic2::toLonLatVec2() const {
return Vec2(lon, lat);
}
Geodetic2 Geodetic2::operator+(const Geodetic2& other) const {
return Geodetic2(lat + other.lat, lon + other.lon);
}
bool Geodetic2::operator==(const Geodetic2& other) const {
return lat == other.lat && lon == other.lon;
}
Geodetic2 Geodetic2::operator-(const Geodetic2& other) const {
return Geodetic2(lat - other.lat, lon - other.lon);
}
Geodetic2 Geodetic2::operator+(const Geodetic2& other) const {
return Geodetic2(lat + other.lat, lon + other.lon);
}
Geodetic2 Geodetic2::operator*(double scalar) const {
return Geodetic2(lat * scalar, lon * scalar);
}
Geodetic2 Geodetic2::operator-(const Geodetic2& other) const {
return Geodetic2(lat - other.lat, lon - other.lon);
}
Geodetic2 Geodetic2::operator/(double scalar) const {
return Geodetic2(lat / scalar, lon / scalar);
}
Geodetic2 Geodetic2::operator*(Scalar scalar) const {
return Geodetic2(lat * scalar, lon * scalar);
}
GeodeticPatch::GeodeticPatch(double centerLat, double centerLon, double halfSizeLat,
double halfSizeLon)
: _center(Geodetic2(centerLat, centerLon))
, _halfSize(Geodetic2(halfSizeLat, halfSizeLon))
{}
Geodetic2 Geodetic2::operator/(Scalar scalar) const {
return Geodetic2(lat / scalar, lon / scalar);
}
GeodeticPatch::GeodeticPatch(const Geodetic2& center, const Geodetic2& halfSize)
: _center(center)
, _halfSize(halfSize)
{}
//////////////////////////////////////////////////////////////////////////////////////
// GEODETICPATCH //
//////////////////////////////////////////////////////////////////////////////////////
GeodeticPatch::GeodeticPatch(const GeodeticPatch& patch)
: _center(patch._center)
, _halfSize(patch._halfSize)
{}
GeodeticPatch::GeodeticPatch(
Scalar centerLat,
Scalar centerLon,
Scalar halfSizeLat,
Scalar halfSizeLon)
: _center(Geodetic2(centerLat, centerLon))
, _halfSize(Geodetic2(halfSizeLat, halfSizeLon))
{}
GeodeticPatch::GeodeticPatch(const TileIndex& tileIndex) {
double deltaLat = (2 * glm::pi<double>()) / ((double)(1 << tileIndex.level));
double deltaLon = (2 * glm::pi<double>()) / ((double)(1 << tileIndex.level));
Geodetic2 nwCorner(glm::pi<double>() / 2 - deltaLat * tileIndex.y, -glm::pi<double>() + deltaLon * tileIndex.x);
_halfSize = Geodetic2(deltaLat / 2, deltaLon / 2);
_center = Geodetic2(nwCorner.lat - _halfSize.lat, nwCorner.lon + _halfSize.lon);
}
GeodeticPatch::GeodeticPatch(
const Geodetic2& center,
const Geodetic2& halfSize)
: _center(center)
, _halfSize(halfSize)
{}
void GeodeticPatch::setCenter(const Geodetic2& center) {
_center = center;
}
GeodeticPatch::GeodeticPatch(const GeodeticPatch& patch)
: _center(patch._center)
, _halfSize(patch._halfSize)
{}
void GeodeticPatch::setHalfSize(const Geodetic2& halfSize) {
_halfSize = halfSize;
}
GeodeticPatch::GeodeticPatch(const TileIndex& tileIndex) {
Scalar deltaLat = (2 * M_PI) / ((double)(1 << tileIndex.level));
Scalar deltaLon = (2 * M_PI) / ((double)(1 << tileIndex.level));
Geodetic2 nwCorner(M_PI / 2 - deltaLat * tileIndex.y, -M_PI + deltaLon * tileIndex.x);
_halfSize = Geodetic2(deltaLat / 2, deltaLon / 2);
_center = Geodetic2(nwCorner.lat - _halfSize.lat, nwCorner.lon + _halfSize.lon);
}
double GeodeticPatch::maximumTileLevel() const {
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
return log2(glm::pi<double>() / glm::min(_halfSize.lat, _halfSize.lon));
}
void GeodeticPatch::setCenter(const Geodetic2& center) {
_center = center;
}
double GeodeticPatch::minimumTileLevel() const {
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
return log2(glm::pi<double>() / glm::max(_halfSize.lat, _halfSize.lon));
}
void GeodeticPatch::setHalfSize(const Geodetic2& halfSize) {
_halfSize = halfSize;
}
const Geodetic2& GeodeticPatch::center() const {
return _center;
}
Scalar GeodeticPatch::maximumTileLevel() const {
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
return log2(M_PI / glm::min(_halfSize.lat, _halfSize.lon));
}
const Geodetic2& GeodeticPatch::halfSize() const {
return _halfSize;
}
Scalar GeodeticPatch::minimumTileLevel() const {
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
return log2(M_PI / glm::max(_halfSize.lat, _halfSize.lon));
}
Geodetic2 GeodeticPatch::size() const {
return Geodetic2(2 * _halfSize.lat, 2 * _halfSize.lon);
}
const Geodetic2& GeodeticPatch::center() const {
return _center;
}
const Geodetic2& GeodeticPatch::halfSize() const {
return _halfSize;
}
Geodetic2 GeodeticPatch::size() const {
return Geodetic2(2 * _halfSize.lat, 2 * _halfSize.lon);
}
Geodetic2 GeodeticPatch::getCorner(Quad q) const {
switch (q) {
Geodetic2 GeodeticPatch::getCorner(Quad q) const {
switch (q) {
case NORTH_WEST: return Geodetic2(maxLat(), minLon());// northWestCorner();
case NORTH_EAST: return Geodetic2(maxLat(), maxLon());// northEastCorner();
case SOUTH_WEST: return Geodetic2(minLat(), minLon());// southWestCorner();
case SOUTH_EAST: return Geodetic2(minLat(), maxLon());// southEastCorner();
}
}
}
Geodetic2 GeodeticPatch::getSize() const {
return _halfSize * 2;
}
Geodetic2 GeodeticPatch::getSize() const {
return _halfSize * 2;
}
double GeodeticPatch::minLat() const {
return _center.lat - _halfSize.lat;
}
Scalar GeodeticPatch::minLat() const {
return _center.lat - _halfSize.lat;
}
double GeodeticPatch::maxLat() const {
return _center.lat + _halfSize.lat;
}
Scalar GeodeticPatch::maxLat() const {
return _center.lat + _halfSize.lat;
}
double GeodeticPatch::minLon() const {
return _center.lon - _halfSize.lon;
}
Scalar GeodeticPatch::minLon() const {
return _center.lon - _halfSize.lon;
}
Scalar GeodeticPatch::maxLon() const {
return _center.lon + _halfSize.lon;
}
double GeodeticPatch::maxLon() const {
return _center.lon + _halfSize.lon;
}
bool GeodeticPatch::contains(const Geodetic2& p) const {
Geodetic2 diff = _center - p;
return glm::abs(diff.lat) <= _halfSize.lat && glm::abs(diff.lon) <= _halfSize.lon;
}
bool GeodeticPatch::contains(const Geodetic2& p) const {
Geodetic2 diff = _center - p;
return glm::abs(diff.lat) <= _halfSize.lat && glm::abs(diff.lon) <= _halfSize.lon;
}
Scalar GeodeticPatch::edgeLatitudeNearestEquator() const {
return _center.lat + _halfSize.lat * (isNorthern() ? -1 : 1);
}
double GeodeticPatch::edgeLatitudeNearestEquator() const {
return _center.lat + _halfSize.lat * (isNorthern() ? -1 : 1);
}
Scalar GeodeticPatch::isNorthern() const {
return _center.lat > 0.0;
}
double GeodeticPatch::isNorthern() const {
return _center.lat > 0.0;
}
Geodetic2 GeodeticPatch::clamp(const Geodetic2& p) const {
using Ang = Angle<Scalar>;
Geodetic2 GeodeticPatch::clamp(const Geodetic2& p) const {
using Ang = Angle<double>;
// Convert to Angles for normalization
Ang centerLat = Ang::fromRadians(_center.lat);
Ang centerLon = Ang::fromRadians(_center.lon);
Ang pointLat = Ang::fromRadians(p.lat);
Ang pointLon = Ang::fromRadians(p.lon);
// Convert to Angles for normalization
Ang centerLat = Ang::fromRadians(_center.lat);
Ang centerLon = Ang::fromRadians(_center.lon);
Ang pointLat = Ang::fromRadians(p.lat);
Ang pointLon = Ang::fromRadians(p.lon);
// Normalize w.r.t. the center in order for the clamping to done correctly
//
// Example:
// centerLat = 0 deg, halfSize.lat = 10 deg, pointLat = 330 deg
// --> Just clamping pointLat would be clamp(330, -10, 10) = 10 // WRONG!
// Instead, if we first normalize 330 deg around 0, we get -30 deg
// --> clamp(-30, -10, 10) = -10 // CORRECT!
pointLat.normalizeAround(centerLat);
pointLon.normalizeAround(centerLon);
// Normalize w.r.t. the center in order for the clamping to done correctly
//
// Example:
// centerLat = 0 deg, halfSize.lat = 10 deg, pointLat = 330 deg
// --> Just clamping pointLat would be clamp(330, -10, 10) = 10 // WRONG!
// Instead, if we first normalize 330 deg around 0, we get -30 deg
// --> clamp(-30, -10, 10) = -10 // CORRECT!
pointLat.normalizeAround(centerLat);
pointLon.normalizeAround(centerLon);
return Geodetic2(
glm::clamp(pointLat.asRadians(), minLat(), maxLat()),
glm::clamp(pointLon.asRadians(), minLon(), maxLon())
);
}
return Geodetic2(
glm::clamp(pointLat.asRadians(), minLat(), maxLat()),
glm::clamp(pointLon.asRadians(), minLon(), maxLon())
);
}
Geodetic2 GeodeticPatch::closestCorner(const Geodetic2& p) const {
using Ang = Angle<Scalar>;
Geodetic2 GeodeticPatch::closestCorner(const Geodetic2& p) const {
using Ang = Angle<double>;
// LatLon vector from patch center to the point
Geodetic2 centerToPoint = p - _center;
// LatLon vector from patch center to the point
Geodetic2 centerToPoint = p - _center;
// Normalize the difference angles to be centered around 0.
Ang latDiff = Ang::fromRadians(centerToPoint.lat).normalizeAround(Ang::ZERO);
Ang lonDiff = Ang::fromRadians(centerToPoint.lon).normalizeAround(Ang::ZERO);
// Normalize the difference angles to be centered around 0.
Ang latDiff = Ang::fromRadians(centerToPoint.lat).normalizeAround(Ang::ZERO);
Ang lonDiff = Ang::fromRadians(centerToPoint.lon).normalizeAround(Ang::ZERO);
// If latDiff > 0
// --> point p is north of the patch center
// --> the closest corner to the point must be a northern one
// --> set the corner's latitude coordinate to center.lat + halfSize.lat
// else
// --> set corner's latidude coordinate to center.lat - halfSize.lat
Scalar cornerLat = _center.lat + _halfSize.lat * (latDiff > Ang::ZERO ? 1 : -1);
// If latDiff > 0
// --> point p is north of the patch center
// --> the closest corner to the point must be a northern one
// --> set the corner's latitude coordinate to center.lat + halfSize.lat
// else
// --> set corner's latidude coordinate to center.lat - halfSize.lat
double cornerLat = _center.lat + _halfSize.lat * (latDiff > Ang::ZERO ? 1 : -1);
// We then assigned the corner's longitude coordinate in a similar fashion
Scalar cornerLon = _center.lon + _halfSize.lon * (lonDiff > Ang::ZERO ? 1 : -1);
// We then assigned the corner's longitude coordinate in a similar fashion
double cornerLon = _center.lon + _halfSize.lon * (lonDiff > Ang::ZERO ? 1 : -1);
return Geodetic2(cornerLat, cornerLon);
}
return Geodetic2(cornerLat, cornerLon);
}
Geodetic2 GeodeticPatch::closestPoint(const Geodetic2& p) const {
// This method finds the closest point on the patch, to the provided
// point p. As we are deali ng with latitude-longitude patches, distance in this
// context refers to great-circle distance.
// (https://en.wikipedia.org/wiki/Great-circle_distance)
//
// This uses a simple clamping approach to find the closest point on the
// patch. A naive castesian clamp is not sufficient for this purpose,
// as illustrated with an example below.
Geodetic2 GeodeticPatch::closestPoint(const Geodetic2& p) const {
// This method finds the closest point on the patch, to the provided
// point p. As we are deali ng with latitude-longitude patches, distance in this
// context refers to great-circle distance.
// (https://en.wikipedia.org/wiki/Great-circle_distance)
//
// This uses a simple clamping approach to find the closest point on the
// patch. A naive castesian clamp is not sufficient for this purpose,
// as illustrated with an example below.
// Example: (degrees are used for latidude, longitude)
// patchCenter = (0,0), patchHalfSize = (45,45), point = (5, 170)
// Note, the point and the patch are on opposite sides of the sphere
//
// cartesian clamp:
// --> clampedPointLat = clamp(5, -45, 45) = 5
// --> clampedPointLon = clamp(170, -45, 45) = 45
// --> result: (5, 45)
// --> closest point is actually (45, 45)
// --> The error is significant
//
// This method simply adds an extra clamp on the latitude in these cases. In the
// above example, that would be the following:
// --> clampedPointLat = clamp(180 - 5, -45, 45) = 45
//
// Just doing this actually makes points returned from this methods being the
// true closest point, great-circle distance-wise.
// Example: (degrees are used for latidude, longitude)
// patchCenter = (0,0), patchHalfSize = (45,45), point = (5, 170)
// Note, the point and the patch are on opposite sides of the sphere
//
// cartesian clamp:
// --> clampedPointLat = clamp(5, -45, 45) = 5
// --> clampedPointLon = clamp(170, -45, 45) = 45
// --> result: (5, 45)
// --> closest point is actually (45, 45)
// --> The error is significant
//
// This method simply adds an extra clamp on the latitude in these cases. In the
// above example, that would be the following:
// --> clampedPointLat = clamp(180 - 5, -45, 45) = 45
//
// Just doing this actually makes points returned from this methods being the
// true closest point, great-circle distance-wise.
using Ang = Angle<Scalar>;
using Ang = Angle<double>;
// Convert to Angles for normalization
Ang centerLat = Ang::fromRadians(_center.lat);
Ang centerLon = Ang::fromRadians(_center.lon);
Ang pointLat = Ang::fromRadians(p.lat);
Ang pointLon = Ang::fromRadians(p.lon);
// Convert to Angles for normalization
Ang centerLat = Ang::fromRadians(_center.lat);
Ang centerLon = Ang::fromRadians(_center.lon);
Ang pointLat = Ang::fromRadians(p.lat);
Ang pointLon = Ang::fromRadians(p.lon);
// Normalize point with respect to center. This is done because the point
// will later be clamped. See LatLonPatch::clamp(const LatLon&) for explanation
pointLat.normalizeAround(centerLat);
pointLon.normalizeAround(centerLon);
// Normalize point with respect to center. This is done because the point
// will later be clamped. See LatLonPatch::clamp(const LatLon&) for explanation
pointLat.normalizeAround(centerLat);
pointLon.normalizeAround(centerLon);
// Calculate the longitud difference between center and point. We normalize around
// zero because we want the "shortest distance" difference, i.e the difference
// should be in the interval [-180 deg, 180 deg]
Ang centerToPointLon = (centerLon - pointLon).normalizeAround(Ang::ZERO);
// Calculate the longitud difference between center and point. We normalize around
// zero because we want the "shortest distance" difference, i.e the difference
// should be in the interval [-180 deg, 180 deg]
Ang centerToPointLon = (centerLon - pointLon).normalizeAround(Ang::ZERO);
// Calculate the longitudinal distance to the closest patch edge
Ang longitudeDistanceToClosestPatchEdge = centerToPointLon.abs() - Ang::fromRadians(_halfSize.lon);
// Calculate the longitudinal distance to the closest patch edge
Ang longitudeDistanceToClosestPatchEdge = centerToPointLon.abs() - Ang::fromRadians(_halfSize.lon);
// If the longitude distance to the closest patch edge is larger than 90 deg
// the latitude will have to be clamped to its closest corner, as explained in
// the example above.
Scalar clampedLat = longitudeDistanceToClosestPatchEdge > Ang::QUARTER ?
clampedLat = glm::clamp((Ang::HALF - pointLat).normalizeAround(centerLat).asRadians(), minLat(), maxLat()) :
clampedLat = glm::clamp(pointLat.asRadians(), minLat(), maxLat());
// If the longitude distance to the closest patch edge is larger than 90 deg
// the latitude will have to be clamped to its closest corner, as explained in
// the example above.
double clampedLat = longitudeDistanceToClosestPatchEdge > Ang::QUARTER ?
clampedLat = glm::clamp((Ang::HALF - pointLat).normalizeAround(centerLat).asRadians(), minLat(), maxLat()) :
clampedLat = glm::clamp(pointLat.asRadians(), minLat(), maxLat());
// Longitude is just clamped normally
Scalar clampedLon = glm::clamp(pointLon.asRadians(), minLon(), maxLon());
// Longitude is just clamped normally
double clampedLon = glm::clamp(pointLon.asRadians(), minLon(), maxLon());
return Geodetic2(clampedLat, clampedLon);
}
return Geodetic2(clampedLat, clampedLon);
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -22,69 +22,51 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __GEODETIC2_H__
#define __GEODETIC2_H__
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <ostream>
#define _USE_MATH_DEFINES
#include <math.h>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_GEODETIC2_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_GEODETIC2_H__
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/misc/assert.h>
// Using double precision
typedef double Scalar;
typedef glm::dvec2 Vec2;
typedef glm::dvec3 Vec3;
#include <ghoul/glm.h>
namespace openspace {
namespace globebrowsing {
// Forward declaration
class Ellipsoid;
struct Geodetic2 {
Geodetic2();
Geodetic2(Scalar latitude, Scalar longitude);
Geodetic2(double latitude = 0.0, double longitude = 0.0);
Geodetic2(const Geodetic2& src);
//static Geodetic2 fromCartesian(const Vec3& v);
//Vec3 asUnitCartesian() const;
Vec2 toLonLatVec2() const;
glm::dvec2 toLonLatVec2() const;
bool operator==(const Geodetic2& other) const;
bool operator!=(const Geodetic2& other) const { return !(*this == (other)); }
Geodetic2 operator+(const Geodetic2& other) const;
Geodetic2 operator-(const Geodetic2& other) const;
Geodetic2 operator*(Scalar scalar) const;
Geodetic2 operator/(Scalar scalar) const;
Geodetic2 operator*(double scalar) const;
Geodetic2 operator/(double scalar) const;
Scalar lat;
Scalar lon;
double lat;
double lon;
};
struct Geodetic3 {
Geodetic2 geodetic2;
Scalar height;
double height;
};
//////////////////////////////////////////////////////////////////////////////////////
// GEODETICPATCH //
//////////////////////////////////////////////////////////////////////////////////////
class GeodeticPatch {
public:
GeodeticPatch(
Scalar centerLat,
Scalar centerLon,
Scalar halfSizeLat,
Scalar halfSizeLon);
double centerLat,
double centerLon,
double halfSizeLat,
double halfSizeLon);
GeodeticPatch(
const Geodetic2& center,
@@ -100,20 +82,20 @@ public:
/**
returns the latitude boundary which is closest to the equator
*/
Scalar edgeLatitudeNearestEquator() const;
double edgeLatitudeNearestEquator() const;
/**
Returns true if the center above the equator
*/
Scalar isNorthern() const;
double isNorthern() const;
Geodetic2 getCorner(Quad q) const;
Geodetic2 getSize() const;
Scalar minLat() const;
Scalar maxLat() const;
Scalar minLon() const;
Scalar maxLon() const;
double minLat() const;
double maxLat() const;
double minLon() const;
double maxLon() const;
/**
* returns true if the specified coordinate is contained within the patch
@@ -140,12 +122,12 @@ public:
/**
* Returns the minimum tile level of the patch (based on largest side)
*/
Scalar minimumTileLevel() const;
double minimumTileLevel() const;
/**
* Returns the maximum level of the patch (based on smallest side)
*/
Scalar maximumTileLevel() const;
double maximumTileLevel() const;
const Geodetic2& center() const;
const Geodetic2& halfSize() const;
@@ -159,4 +141,4 @@ private:
} // namespace globebrowsing
} // namespace openspace
#endif // __GEODETIC2_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_GEODETIC2_H__

View File

@@ -26,6 +26,13 @@
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/other/distanceswitch.h>
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/singleimageprovider.h>
#include <modules/globebrowsing/tile/tileprovider/temporaltileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/texttileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
#include <openspace/rendering/renderable.h>
#include <openspace/util/factorymanager.h>
@@ -33,44 +40,31 @@
#include <ghoul/misc/templatefactory.h>
#include <ghoul/misc/assert.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/singleimageprovider.h>
#include <modules/globebrowsing/tile/tileprovider/temporaltileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/texttileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
namespace openspace {
GlobeBrowsingModule::GlobeBrowsingModule()
: OpenSpaceModule("GlobeBrowsing")
{}
GlobeBrowsingModule::GlobeBrowsingModule() : OpenSpaceModule("GlobeBrowsing") {}
void GlobeBrowsingModule::internalInitialize() {
using namespace globebrowsing;
auto fRenderable = FactoryManager::ref().factory<Renderable>();
ghoul_assert(fRenderable, "Renderable factory was not created");
fRenderable->registerClass<globebrowsing::RenderableGlobe>("RenderableGlobe");
void addFactory(std::unique_ptr<ghoul::TemplateFactoryBase> factory);
// add Tile Provider factory
FactoryManager::ref().addFactory(
std::make_unique<ghoul::TemplateFactory<globebrowsing::TileProvider>>());
auto fTileProvider = std::make_unique<ghoul::TemplateFactory<TileProvider>>();
auto fTileProvider =
FactoryManager::ref().factory<globebrowsing::TileProvider>();
fTileProvider->registerClass<globebrowsing::CachingTileProvider>("LRUCaching");
fTileProvider->registerClass<globebrowsing::SingleImageProvider>("SingleImage");
fTileProvider->registerClass<globebrowsing::TemporalTileProvider>("Temporal");
fTileProvider->registerClass<globebrowsing::TileIndexTileProvider>("TileIndex");
fTileProvider->registerClass<globebrowsing::SizeReferenceTileProvider>("SizeReference");
fTileProvider->registerClass<CachingTileProvider>("LRUCaching");
fTileProvider->registerClass<SingleImageProvider>("SingleImage");
fTileProvider->registerClass<TemporalTileProvider>("Temporal");
fTileProvider->registerClass<TileIndexTileProvider>("TileIndex");
fTileProvider->registerClass<SizeReferenceTileProvider>("SizeReference");
// Combining Tile Providers
fTileProvider->registerClass<globebrowsing::TileProviderByLevel>("ByLevel");
fTileProvider->registerClass<globebrowsing::TileProviderByIndex>("ByIndex");
fTileProvider->registerClass<TileProviderByLevel>("ByLevel");
fTileProvider->registerClass<TileProviderByIndex>("ByIndex");
FactoryManager::ref().addFactory(std::move(fTileProvider));
}
} // namespace openspace

View File

@@ -1,351 +1,321 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/chunk/chunk.h>
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
#include <modules/globebrowsing/chunk/chunknode.h>
#include <modules/globebrowsing/chunk/culling.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/meshes/skirtedgrid.h>
#include <modules/globebrowsing/chunk/culling.h>
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/rendering/chunkrenderer.h>
#include <modules/globebrowsing/rendering/layermanager.h>
#include <modules/debugging/rendering/debugrenderer.h>
// open space includes
#include <openspace/engine/openspaceengine.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/util/spicemanager.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/time.h>
// ghoul includes
#include <ghoul/misc/assert.h>
#include <ghoul/logging/logmanager.h>
// open space includes
#include <openspace/rendering/renderengine.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/util/updatestructures.h>
#include <modules/globebrowsing/chunk/chunknode.h>
#include <modules/globebrowsing/rendering/chunkrenderer.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <ctime>
#include <chrono>
namespace {
const std::string _loggerCat = "ChunkedLodGlobe";
}
#include <ghoul/filesystem/filesystem.h>
namespace openspace {
namespace globebrowsing {
const TileIndex ChunkedLodGlobe::LEFT_HEMISPHERE_INDEX =
TileIndex(0, 0, 1);
const TileIndex ChunkedLodGlobe::RIGHT_HEMISPHERE_INDEX =
TileIndex(1, 0, 1);
const GeodeticPatch ChunkedLodGlobe::COVERAGE =
GeodeticPatch(0, 0, 90, 180);
const TileIndex ChunkedLodGlobe::LEFT_HEMISPHERE_INDEX = TileIndex(0, 0, 1);
const TileIndex ChunkedLodGlobe::RIGHT_HEMISPHERE_INDEX = TileIndex(1, 0, 1);
const GeodeticPatch ChunkedLodGlobe::COVERAGE = GeodeticPatch(0, 0, 90, 180);
ChunkedLodGlobe::ChunkedLodGlobe(
const RenderableGlobe& owner,
size_t segmentsPerPatch,
std::shared_ptr<LayerManager> layerManager)
: _owner(owner)
, _leftRoot(std::make_unique<ChunkNode>(
Chunk(owner, LEFT_HEMISPHERE_INDEX)))
, _rightRoot(std::make_unique<ChunkNode>(
Chunk(owner, RIGHT_HEMISPHERE_INDEX)))
, minSplitDepth(2)
, maxSplitDepth(22)
, _layerManager(layerManager)
, stats(StatsCollector(absPath("test_stats"), 1,
StatsCollector::Enabled::No)) {
auto geometry = std::make_shared<SkirtedGrid>(
(unsigned int) segmentsPerPatch,
(unsigned int) segmentsPerPatch,
TriangleSoup::Positions::No,
TriangleSoup::TextureCoordinates::Yes,
TriangleSoup::Normals::No);
ChunkedLodGlobe::ChunkedLodGlobe(const RenderableGlobe& owner, size_t segmentsPerPatch,
std::shared_ptr<LayerManager> layerManager)
: _owner(owner)
, _leftRoot(std::make_unique<ChunkNode>(Chunk(owner, LEFT_HEMISPHERE_INDEX)))
, _rightRoot(std::make_unique<ChunkNode>(Chunk(owner, RIGHT_HEMISPHERE_INDEX)))
, minSplitDepth(2)
, maxSplitDepth(22)
, _layerManager(layerManager)
, stats(StatsCollector(absPath("test_stats"), 1, StatsCollector::Enabled::No))
{
auto geometry = std::make_shared<SkirtedGrid>(
static_cast<unsigned int>(segmentsPerPatch),
static_cast<unsigned int>(segmentsPerPatch),
TriangleSoup::Positions::No,
TriangleSoup::TextureCoordinates::Yes,
TriangleSoup::Normals::No
);
_chunkCullers.push_back(std::make_unique<HorizonCuller>());
_chunkCullers.push_back(std::make_unique<FrustumCuller>(
AABB3(vec3(-1, -1, 0), vec3(1, 1, 1e35))));
_chunkCullers.push_back(std::make_unique<HorizonCuller>());
_chunkCullers.push_back(std::make_unique<FrustumCuller>(
AABB3(glm::vec3(-1, -1, 0), glm::vec3(1, 1, 1e35)))
);
_chunkEvaluatorByAvailableTiles =
std::make_unique<EvaluateChunkLevelByAvailableTileData>();
_chunkEvaluatorByProjectedArea =
std::make_unique<EvaluateChunkLevelByProjectedArea>();
_chunkEvaluatorByDistance =
std::make_unique<EvaluateChunkLevelByDistance>();
_chunkEvaluatorByAvailableTiles =
std::make_unique<EvaluateChunkLevelByAvailableTileData>();
_chunkEvaluatorByProjectedArea =
std::make_unique<EvaluateChunkLevelByProjectedArea>();
_chunkEvaluatorByDistance =
std::make_unique<EvaluateChunkLevelByDistance>();
_renderer = std::make_unique<ChunkRenderer>(geometry, layerManager);
}
_renderer = std::make_unique<ChunkRenderer>(geometry, layerManager);
}
ChunkedLodGlobe::~ChunkedLodGlobe() {
bool ChunkedLodGlobe::initialize() {
return true;
}
}
bool ChunkedLodGlobe::deinitialize() {
return true;
}
bool ChunkedLodGlobe::initialize() {
return isReady();
}
bool ChunkedLodGlobe::isReady() const {
return true;
}
bool ChunkedLodGlobe::deinitialize() {
std::shared_ptr<LayerManager> ChunkedLodGlobe::layerManager() const {
return _layerManager;
}
bool ChunkedLodGlobe::testIfCullable(const Chunk& chunk,
const RenderData& renderData) const
{
if (_owner.debugProperties().performHorizonCulling &&
_chunkCullers[0]->isCullable(chunk, renderData)) {
return true;
}
if (_owner.debugProperties().performFrustumCulling &&
_chunkCullers[1]->isCullable(chunk, renderData)) {
return true;
}
return false;
}
bool ChunkedLodGlobe::isReady() const {
bool ready = true;
return ready;
const ChunkNode& ChunkedLodGlobe::findChunkNode(const Geodetic2& p) const {
ghoul_assert(COVERAGE.contains(p),
"Point must be in lat [-90, 90] and lon [-180, 180]");
return p.lon < COVERAGE.center().lon ? _leftRoot->find(p) : _rightRoot->find(p);
}
int ChunkedLodGlobe::getDesiredLevel(
const Chunk& chunk, const RenderData& renderData) const {
int desiredLevel = 0;
if (_owner.debugProperties().levelByProjectedAreaElseDistance) {
desiredLevel = _chunkEvaluatorByProjectedArea->getDesiredLevel(chunk, renderData);
}
else {
desiredLevel = _chunkEvaluatorByDistance->getDesiredLevel(chunk, renderData);
}
std::shared_ptr<LayerManager> ChunkedLodGlobe::layerManager() const {
return _layerManager;
int desiredLevelByAvailableData = _chunkEvaluatorByAvailableTiles->getDesiredLevel(
chunk, renderData
);
if (desiredLevelByAvailableData != ChunkLevelEvaluator::UNKNOWN_DESIRED_LEVEL) {
desiredLevel = glm::min(desiredLevel, desiredLevelByAvailableData);
}
bool ChunkedLodGlobe::testIfCullable(
const Chunk& chunk, const RenderData& renderData) const {
if (_owner.debugProperties().performHorizonCulling &&
_chunkCullers[0]->isCullable(chunk, renderData)) {
return true;
}
if (_owner.debugProperties().performFrustumCulling &&
_chunkCullers[1]->isCullable(chunk, renderData)) {
return true;
}
return false;
}
const ChunkNode& ChunkedLodGlobe::findChunkNode(const Geodetic2 p) const {
ghoul_assert(COVERAGE.contains(p),
"Point must be in lat [-90, 90] and lon [-180, 180]");
return
p.lon < COVERAGE.center().lon ?
_leftRoot->find(p) :
_rightRoot->find(p);
}
int ChunkedLodGlobe::getDesiredLevel(
const Chunk& chunk, const RenderData& renderData) const {
int desiredLevel = 0;
if (_owner.debugProperties().levelByProjectedAreaElseDistance) {
desiredLevel = _chunkEvaluatorByProjectedArea->getDesiredLevel(
chunk, renderData);
}
else {
desiredLevel = _chunkEvaluatorByDistance->getDesiredLevel(
chunk, renderData);
}
int desiredLevelByAvailableData =
_chunkEvaluatorByAvailableTiles->getDesiredLevel(chunk, renderData);
if (desiredLevelByAvailableData !=
ChunkLevelEvaluator::UNKNOWN_DESIRED_LEVEL) {
desiredLevel = min(desiredLevel, desiredLevelByAvailableData);
}
desiredLevel = glm::clamp(desiredLevel, minSplitDepth, maxSplitDepth);
return desiredLevel;
}
desiredLevel = glm::clamp(desiredLevel, minSplitDepth, maxSplitDepth);
return desiredLevel;
}
float ChunkedLodGlobe::getHeight(glm::dvec3 position) const {
float height = 0;
float ChunkedLodGlobe::getHeight(glm::dvec3 position) const {
float height = 0;
// Get the uv coordinates to sample from
Geodetic2 geodeticPosition = _owner.ellipsoid().cartesianToGeodetic2(position);
int chunkLevel = findChunkNode(geodeticPosition).getChunk().tileIndex().level;
// Get the uv coordinates to sample from
Geodetic2 geodeticPosition = _owner.ellipsoid().cartesianToGeodetic2(position);
int chunkLevel = findChunkNode(geodeticPosition).getChunk().tileIndex().level;
TileIndex tileIndex = TileIndex(geodeticPosition, chunkLevel);
GeodeticPatch patch = GeodeticPatch(tileIndex);
TileIndex tileIndex = TileIndex(geodeticPosition, chunkLevel);
GeodeticPatch patch = GeodeticPatch(tileIndex);
Geodetic2 geoDiffPatch =
patch.getCorner(Quad::NORTH_EAST) -
patch.getCorner(Quad::SOUTH_WEST);
Geodetic2 geoDiffPoint = geodeticPosition - patch.getCorner(Quad::SOUTH_WEST);
glm::vec2 patchUV = glm::vec2(
geoDiffPoint.lon / geoDiffPatch.lon, geoDiffPoint.lat / geoDiffPatch.lat);
Geodetic2 geoDiffPatch =
patch.getCorner(Quad::NORTH_EAST) - patch.getCorner(Quad::SOUTH_WEST);
// Get the tile providers for the height maps
const auto& heightMapLayers = _layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
Geodetic2 geoDiffPoint = geodeticPosition - patch.getCorner(Quad::SOUTH_WEST);
glm::vec2 patchUV = glm::vec2(
geoDiffPoint.lon / geoDiffPatch.lon,
geoDiffPoint.lat / geoDiffPatch.lat
);
// Get the tile providers for the height maps
const auto& heightMapLayers = _layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
for (const auto& layer : heightMapLayers) {
TileProvider* tileProvider = layer->tileProvider();
// Transform the uv coordinates to the current tile texture
ChunkTile chunkTile = tileProvider->getChunkTile(tileIndex);
const auto& tile = chunkTile.tile;
const auto& uvTransform = chunkTile.uvTransform;
const auto& depthTransform = tileProvider->depthTransform();
if (tile.status != Tile::Status::OK) {
return 0;
}
glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition(
uvTransform,
patchUV,
glm::uvec2(tile.texture->dimensions()));
// Sample and do linear interpolation
// (could possibly be moved as a function in ghoul texture)
// Suggestion: a function in ghoul::opengl::Texture that takes uv coordinates
// in range [0,1] and uses the set interpolation method and clamping.
glm::uvec3 dimensions = tile.texture->dimensions();
glm::vec2 samplePos = transformedUv * glm::vec2(dimensions);
glm::uvec2 samplePos00 = samplePos;
samplePos00 = glm::clamp(
samplePos00, glm::uvec2(0, 0), glm::uvec2(dimensions) - glm::uvec2(1));
glm::vec2 samplePosFract = samplePos - glm::vec2(samplePos00);
glm::uvec2 samplePos10 = glm::min(
samplePos00 + glm::uvec2(1, 0), glm::uvec2(dimensions) - glm::uvec2(1));
glm::uvec2 samplePos01 = glm::min(
samplePos00 + glm::uvec2(0, 1), glm::uvec2(dimensions) - glm::uvec2(1));
glm::uvec2 samplePos11 = glm::min(
samplePos00 + glm::uvec2(1, 1), glm::uvec2(dimensions) - glm::uvec2(1));
float sample00 = tile.texture->texelAsFloat(samplePos00).x;
float sample10 = tile.texture->texelAsFloat(samplePos10).x;
float sample01 = tile.texture->texelAsFloat(samplePos01).x;
float sample11 = tile.texture->texelAsFloat(samplePos11).x;
// In case the texture has NaN or no data values don't use this height map.
bool anySampleIsNaN =
isnan(sample00) ||
isnan(sample01) ||
isnan(sample10) ||
isnan(sample11);
bool anySampleIsNoData =
sample00 == tileProvider->noDataValueAsFloat() ||
sample01 == tileProvider->noDataValueAsFloat() ||
sample10 == tileProvider->noDataValueAsFloat() ||
sample11 == tileProvider->noDataValueAsFloat();
if (anySampleIsNaN || anySampleIsNoData) {
continue;
}
float sample0 = sample00 * (1.0 - samplePosFract.x) + sample10 * samplePosFract.x;
float sample1 = sample01 * (1.0 - samplePosFract.x) + sample11 * samplePosFract.x;
float sample = sample0 * (1.0 - samplePosFract.y) + sample1 * samplePosFract.y;
// Perform depth transform to get the value in meters
height = depthTransform.depthOffset + depthTransform.depthScale * sample;
for (const auto& layer : heightMapLayers) {
TileProvider* tileProvider = layer->tileProvider();
// Transform the uv coordinates to the current tile texture
ChunkTile chunkTile = tileProvider->getChunkTile(tileIndex);
const auto& tile = chunkTile.tile;
const auto& uvTransform = chunkTile.uvTransform;
const auto& depthTransform = tileProvider->depthTransform();
if (tile.status != Tile::Status::OK) {
return 0;
}
// Return the result
return height;
}
void ChunkedLodGlobe::render(const RenderData& data) {
stats.startNewRecord();
auto duration = std::chrono::system_clock::now().time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(
duration).count();
stats.i["time"] = millis;
glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition(
uvTransform,
patchUV,
glm::uvec2(tile.texture->dimensions())
);
_leftRoot->updateChunkTree(data);
_rightRoot->updateChunkTree(data);
// Sample and do linear interpolation
// (could possibly be moved as a function in ghoul texture)
// Suggestion: a function in ghoul::opengl::Texture that takes uv coordinates
// in range [0,1] and uses the set interpolation method and clamping.
// Calculate the MVP matrix
dmat4 viewTransform = dmat4(data.camera.combinedViewMatrix());
dmat4 vp = dmat4(data.camera.projectionMatrix()) * viewTransform;
dmat4 mvp = vp * _owner.modelTransform();
// Render function
auto renderJob = [this, &data, &mvp](const ChunkNode& chunkNode) {
stats.i["chunks nodes"]++;
const Chunk& chunk = chunkNode.getChunk();
if (chunkNode.isLeaf()){
stats.i["leafs chunk nodes"]++;
if (chunk.isVisible()) {
stats.i["rendered chunks"]++;
double t0 = Time::now().j2000Seconds();
_renderer->renderChunk(chunkNode.getChunk(), data);
debugRenderChunk(chunk, mvp);
}
}
};
_leftRoot->breadthFirst(renderJob);
_rightRoot->breadthFirst(renderJob);
//_leftRoot->reverseBreadthFirst(renderJob);
//_rightRoot->reverseBreadthFirst(renderJob);
auto duration2 = std::chrono::system_clock::now().time_since_epoch();
auto millis2 = std::chrono::duration_cast<std::chrono::milliseconds>(duration2).count();
stats.i["chunk globe render time"] = millis2 - millis;
}
void ChunkedLodGlobe::debugRenderChunk(
const Chunk& chunk, const glm::dmat4& mvp) const {
if (_owner.debugProperties().showChunkBounds ||
_owner.debugProperties().showChunkAABB) {
const std::vector<glm::dvec4> modelSpaceCorners =
chunk.getBoundingPolyhedronCorners();
std::vector<glm::vec4> clippingSpaceCorners(8);
AABB3 screenSpaceBounds;
glm::uvec3 dimensions = tile.texture->dimensions();
for (size_t i = 0; i < 8; i++) {
const vec4& clippingSpaceCorner = mvp * modelSpaceCorners[i];
clippingSpaceCorners[i] = clippingSpaceCorner;
glm::vec2 samplePos = transformedUv * glm::vec2(dimensions);
glm::uvec2 samplePos00 = samplePos;
samplePos00 = glm::clamp(
samplePos00,
glm::uvec2(0, 0),
glm::uvec2(dimensions) - glm::uvec2(1)
);
glm::vec2 samplePosFract = samplePos - glm::vec2(samplePos00);
vec3 screenSpaceCorner =
(1.0f / clippingSpaceCorner.w) * clippingSpaceCorner;
screenSpaceBounds.expand(screenSpaceCorner);
}
glm::uvec2 samplePos10 = glm::min(
samplePos00 + glm::uvec2(1, 0),
glm::uvec2(dimensions) - glm::uvec2(1)
);
glm::uvec2 samplePos01 = glm::min(
samplePos00 + glm::uvec2(0, 1),
glm::uvec2(dimensions) - glm::uvec2(1)
);
glm::uvec2 samplePos11 = glm::min(
samplePos00 + glm::uvec2(1, 1),
glm::uvec2(dimensions) - glm::uvec2(1)
);
unsigned int colorBits = 1 + chunk.tileIndex().level % 6;
vec4 color = vec4(colorBits & 1, colorBits & 2, colorBits & 4, 0.3);
float sample00 = tile.texture->texelAsFloat(samplePos00).x;
float sample10 = tile.texture->texelAsFloat(samplePos10).x;
float sample01 = tile.texture->texelAsFloat(samplePos01).x;
float sample11 = tile.texture->texelAsFloat(samplePos11).x;
if (_owner.debugProperties().showChunkBounds) {
DebugRenderer::ref().renderNiceBox(clippingSpaceCorners, color);
}
// In case the texture has NaN or no data values don't use this height map.
bool anySampleIsNaN =
isnan(sample00) ||
isnan(sample01) ||
isnan(sample10) ||
isnan(sample11);
if (_owner.debugProperties().showChunkAABB) {
auto& screenSpacePoints =
DebugRenderer::ref().verticesFor(screenSpaceBounds);
DebugRenderer::ref().renderNiceBox(screenSpacePoints, color);
bool anySampleIsNoData =
sample00 == tileProvider->noDataValueAsFloat() ||
sample01 == tileProvider->noDataValueAsFloat() ||
sample10 == tileProvider->noDataValueAsFloat() ||
sample11 == tileProvider->noDataValueAsFloat();
if (anySampleIsNaN || anySampleIsNoData) {
continue;
}
float sample0 = sample00 * (1.0 - samplePosFract.x) + sample10 * samplePosFract.x;
float sample1 = sample01 * (1.0 - samplePosFract.x) + sample11 * samplePosFract.x;
float sample = sample0 * (1.0 - samplePosFract.y) + sample1 * samplePosFract.y;
// Perform depth transform to get the value in meters
height = depthTransform.depthOffset + depthTransform.depthScale * sample;
}
// Return the result
return height;
}
void ChunkedLodGlobe::render(const RenderData& data) {
stats.startNewRecord();
auto duration = std::chrono::system_clock::now().time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
stats.i["time"] = millis;
_leftRoot->updateChunkTree(data);
_rightRoot->updateChunkTree(data);
// Calculate the MVP matrix
glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix());
glm::dmat4 vp = glm::dmat4(data.camera.projectionMatrix()) * viewTransform;
glm::dmat4 mvp = vp * _owner.modelTransform();
// Render function
auto renderJob = [this, &data, &mvp](const ChunkNode& chunkNode) {
stats.i["chunks nodes"]++;
const Chunk& chunk = chunkNode.getChunk();
if (chunkNode.isLeaf()) {
stats.i["leafs chunk nodes"]++;
if (chunk.isVisible()) {
stats.i["rendered chunks"]++;
double t0 = Time::now().j2000Seconds();
_renderer->renderChunk(chunkNode.getChunk(), data);
debugRenderChunk(chunk, mvp);
}
}
}
};
void ChunkedLodGlobe::update(const UpdateData& data) {
_renderer->update();
_leftRoot->breadthFirst(renderJob);
_rightRoot->breadthFirst(renderJob);
//_leftRoot->reverseBreadthFirst(renderJob);
//_rightRoot->reverseBreadthFirst(renderJob);
auto duration2 = std::chrono::system_clock::now().time_since_epoch();
auto millis2 = std::chrono::duration_cast<std::chrono::milliseconds>(duration2).count();
stats.i["chunk globe render time"] = millis2 - millis;
}
void ChunkedLodGlobe::debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp) const {
if (_owner.debugProperties().showChunkBounds ||
_owner.debugProperties().showChunkAABB)
{
const std::vector<glm::dvec4> modelSpaceCorners =
chunk.getBoundingPolyhedronCorners();
std::vector<glm::vec4> clippingSpaceCorners(8);
AABB3 screenSpaceBounds;
for (size_t i = 0; i < 8; ++i) {
const glm::vec4& clippingSpaceCorner = mvp * modelSpaceCorners[i];
clippingSpaceCorners[i] = clippingSpaceCorner;
glm::vec3 screenSpaceCorner =
(1.0f / clippingSpaceCorner.w) * clippingSpaceCorner;
screenSpaceBounds.expand(screenSpaceCorner);
}
unsigned int colorBits = 1 + chunk.tileIndex().level % 6;
glm::vec4 color = glm::vec4(colorBits & 1, colorBits & 2, colorBits & 4, 0.3);
if (_owner.debugProperties().showChunkBounds) {
DebugRenderer::ref().renderNiceBox(clippingSpaceCorners, color);
}
if (_owner.debugProperties().showChunkAABB) {
auto& screenSpacePoints =
DebugRenderer::ref().verticesFor(screenSpaceBounds);
DebugRenderer::ref().renderNiceBox(screenSpacePoints, color);
}
}
}
void ChunkedLodGlobe::update(const UpdateData& data) {
_renderer->update();
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,34 +1,33 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CHUNKED_LOD_GLOBE__
#define __CHUNKED_LOD_GLOBE__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKED_LOD_GLOBE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKED_LOD_GLOBE_H__
#include <openspace/rendering/renderable.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/other/statscollector.h>
#include <memory>
@@ -36,107 +35,105 @@
namespace openspace {
namespace globebrowsing {
class Chunk;
class ChunkCuller;
class ChunkLevelEvaluator;
class ChunkNode;
class ChunkRenderer;
class LayerManager;
class RenderableGlobe;
class Chunk;
class ChunkCuller;
class ChunkLevelEvaluator;
class ChunkNode;
class ChunkRenderer;
class Geodetic2;
class LayerManager;
class RenderableGlobe;
class ChunkedLodGlobe : public Renderable {
public:
ChunkedLodGlobe(
const RenderableGlobe& owner,
size_t segmentsPerPatch,
std::shared_ptr<LayerManager> layerManager);
virtual ~ChunkedLodGlobe();
class ChunkedLodGlobe : public Renderable {
public:
ChunkedLodGlobe(const RenderableGlobe& owner, size_t segmentsPerPatch,
std::shared_ptr<LayerManager> layerManager);
bool initialize() override;
bool deinitialize() override;
bool isReady() const override;
bool initialize() override;
bool deinitialize() override;
bool isReady() const override;
void render(const RenderData& data) override;
void update(const UpdateData& data) override;
void render(const RenderData& data) override;
void update(const UpdateData& data) override;
/**
* Traverse the chunk tree and find the highest level chunk node.
*
* \param location is given in geodetic coordinates and must be in the range
* latitude [-90. 90] and longitude [-180, 180]. In other words, it must be a
* position defined on the globe in georeferenced coordinates.
*/
const ChunkNode& findChunkNode(const Geodetic2 location) const;
/**
* Traverse the chunk tree and find the highest level chunk node.
*
* \param location is given in geodetic coordinates and must be in the range
* latitude [-90. 90] and longitude [-180, 180]. In other words, it must be a
* position defined on the globe in georeferenced coordinates.
*/
const ChunkNode& findChunkNode(const Geodetic2& location) const;
/**
* Test if a specific chunk can saefely be culled without affecting the rendered
* image.
*
* Goes through all available <code>ChunkCuller</code>s and check if any of them
* allows culling of the <code>Chunk</code>s in question.
*/
bool testIfCullable(const Chunk& chunk, const RenderData& renderData) const;
/**
* Test if a specific chunk can saefely be culled without affecting the rendered
* image.
*
* Goes through all available <code>ChunkCuller</code>s and check if any of them
* allows culling of the <code>Chunk</code>s in question.
*/
bool testIfCullable(const Chunk& chunk, const RenderData& renderData) const;
/**
* Gets the desired level which can be used to determine if a chunk should split
* or merge.
*
* Using <code>ChunkLevelEvaluator</code>s, the desired level can be higher or
* lower than the current level of the <code>Chunks</code>s
* <code>TileIndex</code>. If the desired level is higher than that of the
* <code>Chunk</code>, it wants to split. If it is lower, it wants to merge with
* its siblings.
*/
int getDesiredLevel(const Chunk& chunk, const RenderData& renderData) const;
/**
* Gets the desired level which can be used to determine if a chunk should split
* or merge.
*
* Using <code>ChunkLevelEvaluator</code>s, the desired level can be higher or
* lower than the current level of the <code>Chunks</code>s
* <code>TileIndex</code>. If the desired level is higher than that of the
* <code>Chunk</code>, it wants to split. If it is lower, it wants to merge with
* its siblings.
*/
int getDesiredLevel(const Chunk& chunk, const RenderData& renderData) const;
/**
* Calculates the height from the surface of the reference ellipsoid to the
* heigh mapped surface.
*
* The height can be negative if the height map contains negative values.
*
* \param <code>position</code> is the position of a point that gets geodetically
* projected on the reference ellipsoid. <code>position</code> must be in
* cartesian model space.
* \returns the height from the reference ellipsoid to the globe surface.
*/
float getHeight(glm::dvec3 position) const;
/**
* Calculates the height from the surface of the reference ellipsoid to the
* heigh mapped surface.
*
* The height can be negative if the height map contains negative values.
*
* \param <code>position</code> is the position of a point that gets geodetically
* projected on the reference ellipsoid. <code>position</code> must be in
* cartesian model space.
* \returns the height from the reference ellipsoid to the globe surface.
*/
float getHeight(glm::dvec3 position) const;
const int minSplitDepth;
const int maxSplitDepth;
const int minSplitDepth;
const int maxSplitDepth;
std::shared_ptr<LayerManager> layerManager() const;
std::shared_ptr<LayerManager> layerManager() const;
StatsCollector stats;
StatsCollector stats;
private:
void debugRenderChunk(const Chunk& chunk, const glm::dmat4& data) const;
private:
void debugRenderChunk(const Chunk& chunk, const glm::dmat4& data) const;
static const GeodeticPatch COVERAGE;
static const TileIndex LEFT_HEMISPHERE_INDEX;
static const TileIndex RIGHT_HEMISPHERE_INDEX;
static const GeodeticPatch COVERAGE;
static const TileIndex LEFT_HEMISPHERE_INDEX;
static const TileIndex RIGHT_HEMISPHERE_INDEX;
// Covers all negative longitudes
std::unique_ptr<ChunkNode> _leftRoot;
// Covers all negative longitudes
std::unique_ptr<ChunkNode> _leftRoot;
// Covers all positive longitudes
std::unique_ptr<ChunkNode> _rightRoot;
// Covers all positive longitudes
std::unique_ptr<ChunkNode> _rightRoot;
// the patch used for actual rendering
std::unique_ptr<ChunkRenderer> _renderer;
// the patch used for actual rendering
std::unique_ptr<ChunkRenderer> _renderer;
std::vector<std::unique_ptr<ChunkCuller>> _chunkCullers;
std::vector<std::unique_ptr<ChunkCuller>> _chunkCullers;
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByAvailableTiles;
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByProjectedArea;
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByDistance;
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByAvailableTiles;
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByProjectedArea;
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByDistance;
std::shared_ptr<LayerManager> _layerManager;
std::shared_ptr<LayerManager> _layerManager;
const RenderableGlobe& _owner;
};
const RenderableGlobe& _owner;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __CHUNKED_LOD_GLOBE__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKED_LOD_GLOBE_H__

View File

@@ -1,147 +1,123 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/globes/pointglobe.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
// open space includes
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/util/spicemanager.h>
#include <openspace/scene/scenegraphnode.h>
// ghoul includes
#include <ghoul/misc/assert.h>
#define _USE_MATH_DEFINES
#include <math.h>
namespace {
const std::string _loggerCat = "PointGlobe";
}
namespace openspace {
namespace globebrowsing {
PointGlobe::PointGlobe(const RenderableGlobe& owner)
: _owner(owner) {
PointGlobe::PointGlobe(const RenderableGlobe& owner)
: _owner(owner)
{}
}
PointGlobe::~PointGlobe() {
glDeleteBuffers(1, &_vertexBufferID);
glDeleteVertexArrays(1, &_vaoID);
}
PointGlobe::~PointGlobe() {
glDeleteBuffers(1, &_vertexBufferID);
glDeleteVertexArrays(1, &_vaoID);
}
bool PointGlobe::initialize() {
_programObject = OsEng.renderEngine().buildRenderProgram(
"PointGlobe",
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_fs.glsl");
bool PointGlobe::initialize() {
_programObject = OsEng.renderEngine().buildRenderProgram(
"PointGlobe",
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_fs.glsl");
glGenVertexArrays(1, &_vaoID);
glGenBuffers(1, &_vertexBufferID);
// Create VAO
glGenVertexArrays(1, &_vaoID);
glBindVertexArray(_vaoID);
// Create VBOs
glGenBuffers(1, &_vertexBufferID);
if (_vertexBufferID == 0) {
LERROR("Could not create vertex buffer");
return false;
}
// Vertex data is only one point in the origin
glm::vec3 data = glm::vec3(0,0,0);
// First VAO setup
glBindVertexArray(_vaoID);
// Vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(glm::vec3),
&data,
GL_STATIC_DRAW
);
// Vertex data is only one point in the origin
glm::vec3 data = glm::vec3(0,0,0);
// Position at location 0
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);
// Vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(glm::vec3),
&data,
GL_STATIC_DRAW);
glBindVertexArray(0);
// Position at location 0
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);
return isReady();
}
glBindVertexArray(0);
bool PointGlobe::deinitialize() {
return true;
}
return isReady();
}
bool PointGlobe::deinitialize() {
return true;
}
bool PointGlobe::isReady() const {
bool ready = true;
return ready;
}
bool PointGlobe::isReady() const {
return (_vaoID != 0) && (_vertexBufferID != 0);
}
void PointGlobe::render(const RenderData& data) {
_programObject->activate();
void PointGlobe::render(const RenderData& data) {
_programObject->activate();
// Calculate variables to be used as uniform variables in shader
glm::dvec3 bodyPosition = data.modelTransform.translation;
// Calculate variables to be used as uniform variables in shader
glm::dvec3 bodyPosition = data.modelTransform.translation;
// Model transform and view transform needs to be in double precision
glm::dmat4 modelTransform =
glm::translate(glm::dmat4(1.0), bodyPosition) * // Translation
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); // Scale
glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition));
glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun;
// Model transform and view transform needs to be in double precision
glm::dmat4 modelTransform =
glm::translate(glm::dmat4(1.0), bodyPosition) * // Translation
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); // Scale
glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition));
glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun;
int windowWidth = OsEng.windowWrapper().currentWindowSize().x;
float avgRadius = _owner.ellipsoid().averageRadius();
int windowWidth = OsEng.windowWrapper().currentWindowSize().x;
float avgRadius = _owner.ellipsoid().averageRadius();
_programObject->setUniform("windowWidth", windowWidth);
_programObject->setUniform("globeRadius", avgRadius);
_programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace);
_programObject->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
_programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
_programObject->setUniform("windowWidth", windowWidth);
_programObject->setUniform("globeRadius", avgRadius);
_programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace);
_programObject->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
_programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexBufferID);
glDrawArrays(GL_POINTS, 0, 1);
glBindVertexArray(0);
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexBufferID);
glDrawArrays(GL_POINTS, 0, 1);
glBindVertexArray(0);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
_programObject->deactivate();
}
_programObject->deactivate();
}
void PointGlobe::update(const UpdateData& data) {
}
void PointGlobe::update(const UpdateData& data) {}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,68 +1,62 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __POINT_GLOBE__
#define __POINT_GLOBE__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_POINTGLOBE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_POINTGLOBE_H__
#include <ghoul/logging/logmanager.h>
#include <ghoul/opengl/ghoul_gl.h>
// open space includes
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/renderable.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/util/updatestructures.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
namespace ghoul { namespace opengl {
class ProgramObject;
}}
namespace openspace {
namespace globebrowsing {
using namespace ghoul::opengl;
class RenderableGlobe;
class RenderableGlobe;
class PointGlobe : public Renderable {
public:
PointGlobe(const RenderableGlobe& owner);
virtual ~PointGlobe();
class PointGlobe : public Renderable {
public:
PointGlobe(const RenderableGlobe& owner);
virtual ~PointGlobe();
bool initialize() override;
bool deinitialize() override;
bool isReady() const override;
bool initialize() override;
bool deinitialize() override;
bool isReady() const override;
void render(const RenderData& data) override;
void update(const UpdateData& data) override;
void render(const RenderData& data) override;
void update(const UpdateData& data) override;
private:
const RenderableGlobe& _owner;
std::unique_ptr<ProgramObject> _programObject;
private:
const RenderableGlobe& _owner;
std::unique_ptr<ghoul::opengl::ProgramObject> _programObject;
GLuint _vertexBufferID;
GLuint _vaoID;
};
GLuint _vertexBufferID;
GLuint _vaoID;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __POINT_GLOBE__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_POINTGLOBE_H__

View File

@@ -1,272 +1,250 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
// globe browsing
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/tile/tileselector.h>
#include <modules/globebrowsing/globes/pointglobe.h>
#include <modules/debugging/rendering/debugrenderer.h>
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/rendering/layermanager.h>
// open space includes
#include <openspace/engine/openspaceengine.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/util/spicemanager.h>
#include <openspace/scene/scenegraphnode.h>
#include <modules/debugging/rendering/debugrenderer.h>
// ghoul includes
#include <ghoul/misc/assert.h>
#include <ghoul/misc/threadpool.h>
namespace {
const std::string _loggerCat = "RenderableGlobe";
// Keys for the dictionary
const std::string keyFrame = "Frame";
const std::string keyRadii = "Radii";
const std::string keyInteractionDepthBelowEllipsoid =
"InteractionDepthBelowEllipsoid";
const std::string keyCameraMinHeight = "CameraMinHeight";
const std::string keySegmentsPerPatch = "SegmentsPerPatch";
const std::string keyLayers = "Layers";
const char* keyFrame = "Frame";
const char* keyRadii = "Radii";
const char* keyInteractionDepthBelowEllipsoid = "InteractionDepthBelowEllipsoid";
const char* keyCameraMinHeight = "CameraMinHeight";
const char* keySegmentsPerPatch = "SegmentsPerPatch";
const char* keyLayers = "Layers";
}
namespace openspace {
using namespace properties;
namespace globebrowsing {
RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
: _generalProperties({
properties::BoolProperty("enabled", "Enabled", true),
properties::BoolProperty("performShading", "perform shading", true),
properties::BoolProperty("atmosphere", "atmosphere", false),
properties::FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f),
properties::FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f)
BoolProperty("enabled", "Enabled", true),
BoolProperty("performShading", "perform shading", true),
BoolProperty("atmosphere", "atmosphere", false),
FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f),
FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f)
})
, _debugProperties({
properties::BoolProperty("saveOrThrowCamera", "save or throw camera", false),
properties::BoolProperty("showChunkEdges", "show chunk edges", false),
properties::BoolProperty("showChunkBounds", "show chunk bounds", false),
properties::BoolProperty("showChunkAABB", "show chunk AABB", false),
properties::BoolProperty("showHeightResolution", "show height resolution", false),
properties::BoolProperty("showHeightIntensities", "show height intensities", false),
properties::BoolProperty("performFrustumCulling", "perform frustum culling", true),
properties::BoolProperty("performHorizonCulling", "perform horizon culling", true),
properties::BoolProperty("levelByProjectedAreaElseDistance", "level by projected area (else distance)",false),
properties::BoolProperty("resetTileProviders", "reset tile providers", false),
properties::BoolProperty("toggleEnabledEveryFrame", "toggle enabled every frame", false),
properties::BoolProperty("collectStats", "collect stats", false),
properties::BoolProperty("onlyModelSpaceRendering", "Only Model Space Rendering", false)
})
{
setName("RenderableGlobe");
BoolProperty("saveOrThrowCamera", "save or throw camera", false),
BoolProperty("showChunkEdges", "show chunk edges", false),
BoolProperty("showChunkBounds", "show chunk bounds", false),
BoolProperty("showChunkAABB", "show chunk AABB", false),
BoolProperty("showHeightResolution", "show height resolution", false),
BoolProperty("showHeightIntensities", "show height intensities", false),
BoolProperty("performFrustumCulling", "perform frustum culling", true),
BoolProperty("performHorizonCulling", "perform horizon culling", true),
BoolProperty("levelByProjectedAreaElseDistance", "level by projected area (else distance)",false),
BoolProperty("resetTileProviders", "reset tile providers", false),
BoolProperty("toggleEnabledEveryFrame", "toggle enabled every frame", false),
BoolProperty("collectStats", "collect stats", false),
BoolProperty("onlyModelSpaceRendering", "Only Model Space Rendering", false)
})
{
setName("RenderableGlobe");
dictionary.getValue(keyFrame, _frame);
dictionary.getValue(keyFrame, _frame);
// Read the radii in to its own dictionary
Vec3 radii;
dictionary.getValue(keyRadii, radii);
_ellipsoid = Ellipsoid(radii);
setBoundingSphere(pss(_ellipsoid.averageRadius(), 0.0));
// Read the radii in to its own dictionary
glm::dvec3 radii;
dictionary.getValue(keyRadii, radii);
_ellipsoid = Ellipsoid(radii);
setBoundingSphere(pss(_ellipsoid.averageRadius(), 0.0));
// Ghoul can't read ints from lua dictionaries...
double patchSegmentsd;
dictionary.getValue(keySegmentsPerPatch, patchSegmentsd);
int patchSegments = patchSegmentsd;
// Ghoul can't read ints from lua dictionaries...
double patchSegmentsd;
dictionary.getValue(keySegmentsPerPatch, patchSegmentsd);
int patchSegments = patchSegmentsd;
dictionary.getValue(keyInteractionDepthBelowEllipsoid,
_interactionDepthBelowEllipsoid);
float cameraMinHeight;
dictionary.getValue(keyCameraMinHeight, cameraMinHeight);
_generalProperties.cameraMinHeight.set(cameraMinHeight);
dictionary.getValue(keyInteractionDepthBelowEllipsoid,
_interactionDepthBelowEllipsoid);
float cameraMinHeight;
dictionary.getValue(keyCameraMinHeight, cameraMinHeight);
_generalProperties.cameraMinHeight.set(cameraMinHeight);
// Init layer manager
ghoul::Dictionary layersDictionary;
if(!dictionary.getValue(keyLayers, layersDictionary))
throw ghoul::RuntimeError(keyLayers + " must be specified specified!");
// Init layer manager
ghoul::Dictionary layersDictionary;
if (!dictionary.getValue(keyLayers, layersDictionary))
throw ghoul::RuntimeError(std::string(keyLayers) + " must be specified specified!");
_layerManager = std::make_shared<LayerManager>(layersDictionary);
_layerManager = std::make_shared<LayerManager>(layersDictionary);
_chunkedLodGlobe = std::make_shared<ChunkedLodGlobe>(
*this, patchSegments, _layerManager);
_chunkedLodGlobe = std::make_shared<ChunkedLodGlobe>(
*this, patchSegments, _layerManager);
// This distance will be enough to render the globe as one pixel if the field of
// view is 'fov' radians and the screen resolution is 'res' pixels.
double fov = 2 * M_PI / 6; // 60 degrees
int res = 2880;
double distance = res * _ellipsoid.maximumRadius() / tan(fov / 2);
_distanceSwitch.addSwitchValue(_chunkedLodGlobe, distance);
// This distance will be enough to render the globe as one pixel if the field of
// view is 'fov' radians and the screen resolution is 'res' pixels.
double fov = 2 * glm::pi<double>() / 6; // 60 degrees
int res = 2880;
double distance = res * _ellipsoid.maximumRadius() / tan(fov / 2);
_distanceSwitch.addSwitchValue(_chunkedLodGlobe, distance);
_debugPropertyOwner.setName("Debug");
_texturePropertyOwner.setName("Textures");
_debugPropertyOwner.setName("Debug");
_texturePropertyOwner.setName("Textures");
addProperty(_generalProperties.isEnabled);
addProperty(_generalProperties.atmosphereEnabled);
addProperty(_generalProperties.performShading);
addProperty(_generalProperties.lodScaleFactor);
addProperty(_generalProperties.cameraMinHeight);
addProperty(_generalProperties.isEnabled);
addProperty(_generalProperties.atmosphereEnabled);
addProperty(_generalProperties.performShading);
addProperty(_generalProperties.lodScaleFactor);
addProperty(_generalProperties.cameraMinHeight);
_debugPropertyOwner.addProperty(_debugProperties.saveOrThrowCamera);
_debugPropertyOwner.addProperty(_debugProperties.showChunkEdges);
_debugPropertyOwner.addProperty(_debugProperties.showChunkBounds);
_debugPropertyOwner.addProperty(_debugProperties.showChunkAABB);
_debugPropertyOwner.addProperty(_debugProperties.showHeightResolution);
_debugPropertyOwner.addProperty(_debugProperties.showHeightIntensities);
_debugPropertyOwner.addProperty(_debugProperties.performFrustumCulling);
_debugPropertyOwner.addProperty(_debugProperties.performHorizonCulling);
_debugPropertyOwner.addProperty(
_debugProperties.levelByProjectedAreaElseDistance);
_debugPropertyOwner.addProperty(_debugProperties.resetTileProviders);
_debugPropertyOwner.addProperty(_debugProperties.toggleEnabledEveryFrame);
_debugPropertyOwner.addProperty(_debugProperties.collectStats);
_debugPropertyOwner.addProperty(_debugProperties.onlyModelSpaceRendering);
_debugPropertyOwner.addProperty(_debugProperties.saveOrThrowCamera);
_debugPropertyOwner.addProperty(_debugProperties.showChunkEdges);
_debugPropertyOwner.addProperty(_debugProperties.showChunkBounds);
_debugPropertyOwner.addProperty(_debugProperties.showChunkAABB);
_debugPropertyOwner.addProperty(_debugProperties.showHeightResolution);
_debugPropertyOwner.addProperty(_debugProperties.showHeightIntensities);
_debugPropertyOwner.addProperty(_debugProperties.performFrustumCulling);
_debugPropertyOwner.addProperty(_debugProperties.performHorizonCulling);
_debugPropertyOwner.addProperty(
_debugProperties.levelByProjectedAreaElseDistance
);
_debugPropertyOwner.addProperty(_debugProperties.resetTileProviders);
_debugPropertyOwner.addProperty(_debugProperties.toggleEnabledEveryFrame);
_debugPropertyOwner.addProperty(_debugProperties.collectStats);
_debugPropertyOwner.addProperty(_debugProperties.onlyModelSpaceRendering);
addPropertySubOwner(_debugPropertyOwner);
addPropertySubOwner(_layerManager.get());
addPropertySubOwner(_debugPropertyOwner);
addPropertySubOwner(_layerManager.get());
}
bool RenderableGlobe::initialize() {
return _distanceSwitch.initialize();
}
bool RenderableGlobe::deinitialize() {
return _distanceSwitch.deinitialize();
}
bool RenderableGlobe::isReady() const {
return true;
}
void RenderableGlobe::render(const RenderData& data) {
bool statsEnabled = _debugProperties.collectStats.value();
_chunkedLodGlobe->stats.setEnabled(statsEnabled);
if (_debugProperties.toggleEnabledEveryFrame.value()) {
_generalProperties.isEnabled.setValue(
!_generalProperties.isEnabled.value()
);
}
if (_generalProperties.isEnabled.value()) {
if (_debugProperties.saveOrThrowCamera.value()) {
_debugProperties.saveOrThrowCamera.setValue(false);
RenderableGlobe::~RenderableGlobe() {
}
bool RenderableGlobe::initialize() {
return _distanceSwitch.initialize();
}
bool RenderableGlobe::deinitialize() {
return _distanceSwitch.deinitialize();
}
bool RenderableGlobe::isReady() const {
return _distanceSwitch.isReady();
}
void RenderableGlobe::render(const RenderData& data) {
bool statsEnabled = _debugProperties.collectStats.value();
_chunkedLodGlobe->stats.setEnabled(statsEnabled);
if (_debugProperties.toggleEnabledEveryFrame.value()) {
_generalProperties.isEnabled.setValue(
!_generalProperties.isEnabled.value());
}
if (_generalProperties.isEnabled.value()) {
if (_debugProperties.saveOrThrowCamera.value()) {
_debugProperties.saveOrThrowCamera.setValue(false);
if (savedCamera() == nullptr) { // save camera
LDEBUG("Saving snapshot of camera!");
setSaveCamera(std::make_shared<Camera>(data.camera));
}
else { // throw camera
LDEBUG("Throwing away saved camera!");
setSaveCamera(nullptr);
}
if (savedCamera() == nullptr) { // save camera
setSaveCamera(std::make_shared<Camera>(data.camera));
}
else { // throw camera
setSaveCamera(nullptr);
}
_distanceSwitch.render(data);
}
if (_savedCamera != nullptr) {
DebugRenderer::ref().renderCameraFrustum(data, *_savedCamera);
}
_distanceSwitch.render(data);
}
void RenderableGlobe::update(const UpdateData& data) {
_time = data.time;
_distanceSwitch.update(data);
glm::dmat4 translation =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation);
glm::dmat4 rotation = glm::dmat4(data.modelTransform.rotation);
glm::dmat4 scaling =
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale,
data.modelTransform.scale, data.modelTransform.scale));
_cachedModelTransform = translation * rotation * scaling;
_cachedInverseModelTransform = glm::inverse(_cachedModelTransform);
if (_debugProperties.resetTileProviders) {
_layerManager->reset();
_debugProperties.resetTileProviders = false;
}
_layerManager->update();
_chunkedLodGlobe->update(data);
if (_savedCamera != nullptr) {
DebugRenderer::ref().renderCameraFrustum(data, *_savedCamera);
}
}
glm::dvec3 RenderableGlobe::projectOnEllipsoid(glm::dvec3 position) {
return _ellipsoid.geodeticSurfaceProjection(position);
}
void RenderableGlobe::update(const UpdateData& data) {
_time = data.time;
_distanceSwitch.update(data);
float RenderableGlobe::getHeight(glm::dvec3 position) {
if (_chunkedLodGlobe) {
return _chunkedLodGlobe->getHeight(position);
}
else {
return 0;
}
}
glm::dmat4 translation =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation);
glm::dmat4 rotation = glm::dmat4(data.modelTransform.rotation);
glm::dmat4 scaling =
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale,
data.modelTransform.scale, data.modelTransform.scale));
std::shared_ptr<ChunkedLodGlobe> RenderableGlobe::chunkedLodGlobe() const{
return _chunkedLodGlobe;
}
_cachedModelTransform = translation * rotation * scaling;
_cachedInverseModelTransform = glm::inverse(_cachedModelTransform);
const Ellipsoid& RenderableGlobe::ellipsoid() const{
return _ellipsoid;
if (_debugProperties.resetTileProviders) {
_layerManager->reset();
_debugProperties.resetTileProviders = false;
}
_layerManager->update();
_chunkedLodGlobe->update(data);
}
const glm::dmat4& RenderableGlobe::modelTransform() const{
return _cachedModelTransform;
}
glm::dvec3 RenderableGlobe::projectOnEllipsoid(glm::dvec3 position) {
return _ellipsoid.geodeticSurfaceProjection(position);
}
const glm::dmat4& RenderableGlobe::inverseModelTransform() const{
return _cachedInverseModelTransform;
float RenderableGlobe::getHeight(glm::dvec3 position) {
if (_chunkedLodGlobe) {
return _chunkedLodGlobe->getHeight(position);
}
else {
return 0;
}
}
const RenderableGlobe::DebugProperties&
RenderableGlobe::debugProperties() const{
return _debugProperties;
}
std::shared_ptr<ChunkedLodGlobe> RenderableGlobe::chunkedLodGlobe() const{
return _chunkedLodGlobe;
}
const Ellipsoid& RenderableGlobe::ellipsoid() const{
return _ellipsoid;
}
const glm::dmat4& RenderableGlobe::modelTransform() const{
return _cachedModelTransform;
}
const glm::dmat4& RenderableGlobe::inverseModelTransform() const{
return _cachedInverseModelTransform;
}
const RenderableGlobe::DebugProperties&
RenderableGlobe::debugProperties() const{
return _debugProperties;
}
const RenderableGlobe::GeneralProperties&
RenderableGlobe::generalProperties() const{
return _generalProperties;
}
const RenderableGlobe::GeneralProperties&
RenderableGlobe::generalProperties() const{
return _generalProperties;
}
const std::shared_ptr<const Camera> RenderableGlobe::savedCamera() const {
return _savedCamera;
}
const std::shared_ptr<const Camera> RenderableGlobe::savedCamera() const {
return _savedCamera;
}
double RenderableGlobe::interactionDepthBelowEllipsoid() {
return _interactionDepthBelowEllipsoid;
}
double RenderableGlobe::interactionDepthBelowEllipsoid() {
return _interactionDepthBelowEllipsoid;
}
void RenderableGlobe::setSaveCamera(std::shared_ptr<Camera> camera) {
_savedCamera = camera;
}
void RenderableGlobe::setSaveCamera(std::shared_ptr<Camera> camera) {
_savedCamera = camera;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,47 +1,36 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __RENDERABLEGLOBE_H__
#define __RENDERABLEGLOBE_H__
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/threadpool.h>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_RENDERABLEGLOBE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_RENDERABLEGLOBE_H__
#include <openspace/rendering/renderable.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/selectionproperty.h>
#include <openspace/util/updatestructures.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
#include <modules/globebrowsing/meshes/trianglesoup.h>
#include <modules/globebrowsing/other/distanceswitch.h>
#include <unordered_map>
#include <openspace/properties/scalar/floatproperty.h>
namespace openspace {
namespace globebrowsing {
@@ -55,13 +44,13 @@ class LayerManager;
* The renderable uses a <code>DistanceSwitch</code> to determine if the renderable
* should be rendered.
*/
*/
class RenderableGlobe : public Renderable {
public:
/**
* These properties are specific for <code>ChunkedLodGlobe</code> and separated from
* the general properties of <code>RenderableGlobe</code>.
*/
*/
struct DebugProperties {
properties::BoolProperty saveOrThrowCamera;
properties::BoolProperty showChunkEdges;
@@ -87,7 +76,7 @@ public:
};
RenderableGlobe(const ghoul::Dictionary& dictionary);
~RenderableGlobe();
~RenderableGlobe() = default;
bool initialize() override;
bool deinitialize() override;
@@ -139,4 +128,4 @@ private:
} // namespace globebrowsing
} // namespace openspace
#endif // __RENDERABLEGLOBE_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_RENDERABLEGLOBE_H__

View File

@@ -1,69 +1,60 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/meshes/basicgrid.h>
namespace {
const std::string _loggerCat = "BasicGrid";
}
#include <ghoul/misc/assert.h>
namespace openspace {
namespace globebrowsing {
BasicGrid::BasicGrid(
unsigned int xSegments,
unsigned int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextureCoordinates,
TriangleSoup::Normals useNormals)
: Grid(
xSegments,
ySegments,
usePositions,
useTextureCoordinates,
useNormals)
BasicGrid::BasicGrid(unsigned int xSegments, unsigned int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextureCoordinates,
TriangleSoup::Normals useNormals)
: Grid(xSegments, ySegments, usePositions, useTextureCoordinates, useNormals)
{
_geometry = std::unique_ptr<TriangleSoup>(new TriangleSoup(
_geometry = std::make_unique<TriangleSoup>(
CreateElements(xSegments, ySegments),
usePositions,
useTextureCoordinates,
useNormals));
useNormals
);
if (usePositions == TriangleSoup::Positions::Yes) {
if (usePositions) {
_geometry->setVertexPositions(CreatePositions(_xSegments, _ySegments));
}
if (useTextureCoordinates == TriangleSoup::TextureCoordinates::Yes) {
_geometry->setVertexTextureCoordinates(CreateTextureCoordinates(_xSegments, _ySegments));
if (useTextureCoordinates) {
_geometry->setVertexTextureCoordinates(
CreateTextureCoordinates(_xSegments, _ySegments)
);
}
if (useNormals == TriangleSoup::Normals::Yes) {
if (useNormals) {
_geometry->setVertexNormals(CreateNormals(_xSegments, _ySegments));
}
}
BasicGrid::~BasicGrid()
{}
int BasicGrid::xSegments() const {
return _xSegments;
}
@@ -77,7 +68,7 @@ void BasicGrid::validate(int xSegments, int ySegments) {
"Resolution must be at least 1x1. (" << xSegments << ", " << ySegments << ")");
}
inline size_t BasicGrid::numElements(int xSegments, int ySegments){
inline size_t BasicGrid::numElements(int xSegments, int ySegments) {
return 3 * 2 * xSegments * ySegments;
}
@@ -120,28 +111,29 @@ std::vector<GLuint> BasicGrid::CreateElements(int xSegments, int ySegments) {
return elements;
}
std::vector<glm::vec4> BasicGrid::CreatePositions(
int xSegments,
int ySegments)
{
std::vector<glm::vec4> BasicGrid::CreatePositions(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<glm::vec4> positions;
positions.reserve(numVertices(xSegments, ySegments));
// Copy from 2d texture coordinates and use as template to create positions
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(xSegments, ySegments);
for (unsigned int i = 0; i < templateTextureCoords.size(); i++)
{
positions.push_back(glm::vec4(
templateTextureCoords[i],
0.0f,
1.0f
));
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(
xSegments, ySegments
);
for (const glm::vec2& coords : templateTextureCoords) {
positions.push_back(glm::vec4(coords, 0.f, 1.f));
}
//for (unsigned int i = 0; i < templateTextureCoords.size(); i++) {
// positions.push_back(glm::vec4(
// templateTextureCoords[i],
// 0.0f,
// 1.0f
// ));
//}
return positions;
}
std::vector<glm::vec2> BasicGrid::CreateTextureCoordinates(int xSegments, int ySegments){
std::vector<glm::vec2> BasicGrid::CreateTextureCoordinates(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<glm::vec2> textureCoordinates;
textureCoordinates.reserve(numVertices(xSegments, ySegments));
@@ -172,4 +164,4 @@ std::vector<glm::vec3> BasicGrid::CreateNormals(int xSegments, int ySegments) {
}
} // namespace globebrowsing
} // namespace openspace
} // namespace openspace

View File

@@ -22,39 +22,34 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __BASICGRIDGEOMETRY_H__
#define __BASICGRIDGEOMETRY_H__
#include <glm/glm.hpp>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_BASICGRIDGEOMETRY_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_BASICGRIDGEOMETRY_H__
#include <modules/globebrowsing/meshes/grid.h>
#include <glm/glm.hpp>
#include <vector>
namespace openspace {
namespace globebrowsing {
class BasicGrid : public Grid
{
class BasicGrid : public Grid {
public:
/**
\param xSegments is the number of grid cells in the x direction.
\param ySegments is the number of grid cells in the y direction.
\param usePositions determines whether or not to upload any vertex position data
to the GPU.
\param useTextureCoordinates determines whether or not to upload any vertex texture
coordinate data to the GPU.
\param useNormals determines whether or not to upload any vertex normal data
to the GPU.
* \param xSegments is the number of grid cells in the x direction.
* \param ySegments is the number of grid cells in the y direction.
* \param usePositions determines whether or not to upload any vertex position data
* to the GPU.
* \param useTextureCoordinates determines whether or not to upload any vertex texture
* coordinate data to the GPU.
* \param useNormals determines whether or not to upload any vertex normal data
* to the GPU.
*/
BasicGrid(
unsigned int xSegments,
unsigned int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextureCoordinates,
TriangleSoup::Normals useNormals);
~BasicGrid();
BasicGrid(unsigned int xSegments, unsigned int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextureCoordinates,
TriangleSoup::Normals useNormals);
virtual int xSegments() const;
virtual int ySegments() const;
@@ -74,4 +69,4 @@ private:
} // namespace globebrowsing
} // namespace openspace
#endif // __BASICGRIDGEOMETRY_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_BASICGRIDGEOMETRY_H__

View File

@@ -1,53 +1,41 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/meshes/grid.h>
namespace {
const std::string _loggerCat = "Grid";
}
namespace openspace {
namespace globebrowsing {
Grid::Grid(
int xSegments,
int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextures,
TriangleSoup::Normals useNormals)
Grid::Grid(int xSegments, int ySegments, TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextures, TriangleSoup::Normals useNormals)
: _xSegments(xSegments)
, _ySegments(ySegments)
{}
Grid::~Grid()
{}
TriangleSoup& Grid::geometry()
{
TriangleSoup& Grid::geometry() {
return *_geometry;
}
} // namespace globebrowsing
} // namespace openspace
} // namespace openspace

View File

@@ -1,100 +1,98 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __GRIDGEOMETRY_H__
#define __GRIDGEOMETRY_H__
#include <ghoul/opengl/ghoul_gl.h>
#include <glm/glm.hpp>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_GRIDGEOMETRY_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_GRIDGEOMETRY_H__
#include <modules/globebrowsing/meshes/trianglesoup.h>
#include <glm/glm.hpp>
#include <memory>
#include <vector>
namespace openspace {
namespace globebrowsing {
/**
* Abstract class defining an interface used for geometries with grid structures.
* The class <code>Grid</code> should be extended for use of geometries with a 2D
* structure where the number of segments in x and y direction represents the number
* of vertices + 1 in each direction.
*/
class Grid
{
* Abstract class defining an interface used for geometries with grid structures.
* The class <code>Grid</code> should be extended for use of geometries with a 2D
* structure where the number of segments in x and y direction represents the number
* of vertices + 1 in each direction.
*/
class Grid {
public:
Grid(
int xSegments,
int ySegments,
Grid(int xSegments, int ySegments,
TriangleSoup::Positions usePositions = TriangleSoup::Positions::No,
TriangleSoup::TextureCoordinates useTextures =
TriangleSoup::TextureCoordinates::No,
TriangleSoup::TextureCoordinates::No,
TriangleSoup::Normals useNormals = TriangleSoup::Normals::No);
~Grid();
virtual ~Grid() = default;
TriangleSoup& geometry();
/**
* Returns the number of grid cells in the x direction. Hence the number of vertices
* in the x direction is xResolution + 1.
*/
* Returns the number of grid cells in the x direction. Hence the number of vertices
* in the x direction is xResolution + 1.
*/
virtual int xSegments() const = 0;
/**
* Returns the number of grid cells in the y direction. Hence the number of vertices
* in the y direction is xResolution + 1.
*/
* Returns the number of grid cells in the y direction. Hence the number of vertices
* in the y direction is xResolution + 1.
*/
virtual int ySegments() const = 0;
protected:
/**
* Should return the indices of vertices for a grid with size <code>xSegments</code> *
* <code>ySegments</code>. Where the number of vertices in each direction is the number
* of segments + 1.
*/
* Should return the indices of vertices for a grid with size <code>xSegments</code> *
* <code>ySegments</code>. Where the number of vertices in each direction is the number
* of segments + 1.
*/
virtual std::vector<GLuint> CreateElements(int xSegments, int ySegments) = 0;
/**
* Should return the positions of vertices for a grid with size <code>xSegments</code>
* * <code>ySegments</code>. Where the number of vertices in each direction is the
* number of segments + 1.
*/
* Should return the positions of vertices for a grid with size <code>xSegments</code>
* * <code>ySegments</code>. Where the number of vertices in each direction is the
* number of segments + 1.
*/
virtual std::vector<glm::vec4> CreatePositions(int xSegments, int ySegments) = 0;
/**
* Should return the texture coordinates of vertices for a grid with size
* <code>xSegments</code> * <code>ySegments</code>. Where the number of vertices in
* each direction is the number of segments + 1.
*/
* Should return the texture coordinates of vertices for a grid with size
* <code>xSegments</code> * <code>ySegments</code>. Where the number of vertices in
* each direction is the number of segments + 1.
*/
virtual std::vector<glm::vec2>
CreateTextureCoordinates(int xSegments, int ySegments) = 0;
/**
* Should return the normals of vertices for a grid with size <code>xSegments</code> *
* <code>ySegments</code>. Where the number of vertices in each direction is the number
* of segments + 1.
*/
* Should return the normals of vertices for a grid with size <code>xSegments</code> *
* <code>ySegments</code>. Where the number of vertices in each direction is the number
* of segments + 1.
*/
virtual std::vector<glm::vec3> CreateNormals(int xSegments, int ySegments) = 0;
std::unique_ptr<TriangleSoup> _geometry;
@@ -106,4 +104,4 @@ protected:
} // namespace globebrowsing
} // namespace openspace
#endif // __GRIDGEOMETRY_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_GRIDGEOMETRY_H__

View File

@@ -1,177 +1,180 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/meshes/skirtedgrid.h>
#include <ghoul/misc/assert.h>
namespace {
const std::string _loggerCat = "SkirtedGrid";
const char*_loggerCat = "SkirtedGrid";
}
namespace openspace {
namespace globebrowsing {
SkirtedGrid::SkirtedGrid(
unsigned int xSegments,
unsigned int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextureCoordinates,
TriangleSoup::Normals useNormals)
: Grid(
xSegments,
ySegments,
usePositions,
useTextureCoordinates,
useNormals)
{
_geometry = std::unique_ptr<TriangleSoup>(new TriangleSoup(
CreateElements(xSegments, ySegments),
usePositions,
useTextureCoordinates,
useNormals));
SkirtedGrid::SkirtedGrid(unsigned int xSegments, unsigned int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextureCoordinates,
TriangleSoup::Normals useNormals)
: Grid(xSegments, ySegments, usePositions, useTextureCoordinates, useNormals)
{
_geometry = std::make_unique<TriangleSoup>(
CreateElements(xSegments, ySegments),
usePositions,
useTextureCoordinates,
useNormals
);
if (usePositions == TriangleSoup::Positions::Yes) {
_geometry->setVertexPositions(CreatePositions(_xSegments, _ySegments));
}
if (useTextureCoordinates == TriangleSoup::TextureCoordinates::Yes) {
_geometry->setVertexTextureCoordinates(CreateTextureCoordinates(_xSegments, _ySegments));
}
if (useNormals == TriangleSoup::Normals::Yes) {
_geometry->setVertexNormals(CreateNormals(_xSegments, _ySegments));
if (usePositions) {
_geometry->setVertexPositions(CreatePositions(_xSegments, _ySegments));
}
if (useTextureCoordinates) {
_geometry->setVertexTextureCoordinates(CreateTextureCoordinates(_xSegments, _ySegments));
}
if (useNormals) {
_geometry->setVertexNormals(CreateNormals(_xSegments, _ySegments));
}
}
int SkirtedGrid::xSegments() const {
return _xSegments;
}
int SkirtedGrid::ySegments() const {
return _ySegments;
}
void SkirtedGrid::validate(int xSegments, int ySegments) {
ghoul_assert(
xSegments > 0 && ySegments > 0,
"Resolution must be at least 1x1. (" + std::to_string(xSegments) + ", " + std::to_string(ySegments) + ")"
);
}
inline size_t SkirtedGrid::numElements(int xSegments, int ySegments) {
return 3 * 2 * xSegments * ySegments;
}
inline size_t SkirtedGrid::numVertices(int xSegments, int ySegments) {
return (xSegments + 1) * (ySegments + 1);
}
std::vector<GLuint> SkirtedGrid::CreateElements(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<GLuint> elements;
elements.reserve(numElements(xSegments + 2, ySegments + 2));
for (unsigned int y = 0; y < ySegments + 2; y++) {
for (unsigned int x = 0; x < xSegments + 2; x++) {
// x v01---v11 x ..
// | / |
// x v00---v10 x ..
//
// x x x x ..
// : : : :
GLuint v00 = (y + 0) * (xSegments + 2 + 1) + x + 0;
GLuint v10 = (y + 0) * (xSegments + 2 + 1) + x + 1;
GLuint v01 = (y + 1) * (xSegments + 2 + 1) + x + 0;
GLuint v11 = (y + 1) * (xSegments + 2 + 1) + x + 1;
// add upper triangle
elements.push_back(v00);
elements.push_back(v10);
elements.push_back(v11);
// add lower triangle
elements.push_back(v00);
elements.push_back(v11);
elements.push_back(v01);
}
}
SkirtedGrid::~SkirtedGrid()
{
return elements;
}
std::vector<glm::vec4> SkirtedGrid::CreatePositions(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<glm::vec4> positions;
positions.reserve(numVertices(xSegments, ySegments));
// Copy from 2d texture coordinates and use as template to create positions
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(
xSegments, ySegments
);
for (const auto& c : templateTextureCoords) {
positions.push_back(glm::vec4(c, 0.f, 1.f));
}
//for (unsigned int i = 0; i < templateTextureCoords.size(); i++) {
// positions.push_back(glm::vec4(
// templateTextureCoords[i],
// 0.0f,
// 1.0f
// ));
//}
return positions;
}
int SkirtedGrid::xSegments() const {
return _xSegments;
}
std::vector<glm::vec2> SkirtedGrid::CreateTextureCoordinates(int xSegments, int ySegments)
{
validate(xSegments, ySegments);
std::vector<glm::vec2> textureCoordinates;
textureCoordinates.reserve(numVertices(xSegments + 2, ySegments + 2));
int SkirtedGrid::ySegments() const {
return _ySegments;
}
void SkirtedGrid::validate(int xSegments, int ySegments) {
ghoul_assert(xSegments > 0 && ySegments > 0,
"Resolution must be at least 1x1. (" << xSegments << ", " << ySegments << ")");
}
inline size_t SkirtedGrid::numElements(int xSegments, int ySegments) {
return 3 * 2 * xSegments * ySegments;
}
inline size_t SkirtedGrid::numVertices(int xSegments, int ySegments) {
return (xSegments + 1) * (ySegments + 1);
}
std::vector<GLuint> SkirtedGrid::CreateElements(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<GLuint> elements;
elements.reserve(numElements(xSegments + 2, ySegments + 2));
for (unsigned int y = 0; y < ySegments + 2; y++) {
for (unsigned int x = 0; x < xSegments + 2; x++) {
// x v01---v11 x ..
// | / |
// x v00---v10 x ..
//
// x x x x ..
// : : : :
GLuint v00 = (y + 0) * (xSegments + 2 + 1) + x + 0;
GLuint v10 = (y + 0) * (xSegments + 2 + 1) + x + 1;
GLuint v01 = (y + 1) * (xSegments + 2 + 1) + x + 0;
GLuint v11 = (y + 1) * (xSegments + 2 + 1) + x + 1;
// add upper triangle
elements.push_back(v00);
elements.push_back(v10);
elements.push_back(v11);
// add lower triangle
elements.push_back(v00);
elements.push_back(v11);
elements.push_back(v01);
}
for (int y = -1; y < ySegments + 2; y++) {
for (int x = -1; x < xSegments + 2; x++) {
textureCoordinates.push_back(glm::vec2(
glm::clamp(
static_cast<float>(x) / static_cast<float>(xSegments),
0 - 1.0f / (2 * xSegments),
1 + 1.0f / (2 * xSegments)
),
glm::clamp(
static_cast<float>(y) / static_cast<float>(ySegments),
0 - 1.0f / (2 * ySegments),
1 + 1.0f / (2 * ySegments)
)
));
}
return elements;
}
return textureCoordinates;
}
std::vector<glm::vec4> SkirtedGrid::CreatePositions(
int xSegments,
int ySegments)
{
validate(xSegments, ySegments);
std::vector<glm::vec4> positions;
positions.reserve(numVertices(xSegments, ySegments));
std::vector<glm::vec3> SkirtedGrid::CreateNormals(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<glm::vec3> normals;
normals.reserve(numVertices(xSegments + 2, ySegments + 2));
// Copy from 2d texture coordinates and use as template to create positions
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(xSegments, ySegments);
for (unsigned int i = 0; i < templateTextureCoords.size(); i++)
{
positions.push_back(glm::vec4(
templateTextureCoords[i],
0.0f,
1.0f
));
for (int y = -1; y < ySegments + 2; y++) {
for (int x = -1; x < xSegments + 2; x++) {
normals.push_back(glm::vec3(0, 0, 1));
}
return positions;
}
std::vector<glm::vec2> SkirtedGrid::CreateTextureCoordinates(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<glm::vec2> textureCoordinates;
textureCoordinates.reserve(numVertices(xSegments + 2, ySegments + 2));
for (int y = -1; y < ySegments + 2; y++) {
for (int x = -1; x < xSegments + 2; x++) {
textureCoordinates.push_back(glm::vec2(
glm::clamp(static_cast<float>(x) / static_cast<float>(xSegments), 0 - 1.0f / (2 * xSegments), 1 + 1.0f / (2 * xSegments)),
glm::clamp(static_cast<float>(y) / static_cast<float>(ySegments), 0 - 1.0f / (2 * ySegments), 1 + 1.0f / (2 * ySegments))
));
}
}
return textureCoordinates;
}
std::vector<glm::vec3> SkirtedGrid::CreateNormals(int xSegments, int ySegments) {
validate(xSegments, ySegments);
std::vector<glm::vec3> normals;
normals.reserve(numVertices(xSegments + 2, ySegments + 2));
for (int y = -1; y < ySegments + 2; y++) {
for (int x = -1; x < xSegments + 2; x++) {
normals.push_back(glm::vec3(0, 0, 1));
}
}
return normals;
}
return normals;
}
} // namespace globebrowsing
} // namespace openspace
} // namespace openspace

View File

@@ -1,82 +1,78 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __SKIRTEDGRID_H__
#define __SKIRTEDGRID_H__
#include <glm/glm.hpp>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_SKIRTEDGRID_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_SKIRTEDGRID_H__
#include <modules/globebrowsing/meshes/basicgrid.h>
#include <glm/glm.hpp>
#include <vector>
namespace openspace {
namespace globebrowsing {
/**
* This grid is the same as <code>BasicGrid</code> except it has skirts around its edges.
* The areas covered by the skirts have position coordinates and texture coordinates
* that are outside of the range [0, 1]. The width of the skirts is half the size of one
* segment width or a cell.
*/
class SkirtedGrid : public Grid
{
* This grid is the same as <code>BasicGrid</code> except it has skirts around its edges.
* The areas covered by the skirts have position coordinates and texture coordinates
* that are outside of the range [0, 1]. The width of the skirts is half the size of one
* segment width or a cell.
*/
class SkirtedGrid : public Grid {
public:
/**
* \param xSegments is the number of grid cells in the x direction.
* \param ySegments is the number of grid cells in the y direction.
* \param usePositions determines whether or not to upload any vertex position data
* to the GPU.
* \param useTextureCoordinates determines whether or not to upload any vertex texture
* coordinate data to the GPU.
* \param useNormals determines whether or not to upload any vertex normal data
* to the GPU.
*/
SkirtedGrid(
unsigned int xSegments,
unsigned int ySegments,
* \param xSegments is the number of grid cells in the x direction.
* \param ySegments is the number of grid cells in the y direction.
* \param usePositions determines whether or not to upload any vertex position data
* to the GPU.
* \param useTextureCoordinates determines whether or not to upload any vertex texture
* coordinate data to the GPU.
* \param useNormals determines whether or not to upload any vertex normal data
* to the GPU.
*/
SkirtedGrid(unsigned int xSegments, unsigned int ySegments,
TriangleSoup::Positions usePositions,
TriangleSoup::TextureCoordinates useTextureCoordinates,
TriangleSoup::Normals useNormals);
~SkirtedGrid();
~SkirtedGrid() = default;
virtual int xSegments() const;
virtual int ySegments() const;
private:
virtual std::vector<GLuint> CreateElements(int xRes, int yRes);
virtual std::vector<glm::vec4> CreatePositions(int xRes, int yRes);
virtual std::vector<glm::vec2> CreateTextureCoordinates(int xRes, int yRes);
virtual std::vector<glm::vec3> CreateNormals(int xRes, int yRes);
virtual std::vector<GLuint> CreateElements(int xRes, int yRes);
virtual std::vector<glm::vec4> CreatePositions(int xRes, int yRes);
virtual std::vector<glm::vec2> CreateTextureCoordinates(int xRes, int yRes);
virtual std::vector<glm::vec3> CreateNormals(int xRes, int yRes);
void validate(int xSegments, int ySegments);
inline size_t numElements(int xSegments, int ySegments);
inline size_t numVertices(int xSegments, int ySegments);
size_t numElements(int xSegments, int ySegments);
size_t numVertices(int xSegments, int ySegments);
};
} // namespace globebrowsing
} // namespace openspace
#endif // __SKIRTEDGRID_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_SKIRTEDGRID_H__

View File

@@ -1,29 +1,31 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/meshes/trianglesoup.h>
#include <ghoul/logging/logmanager.h>
namespace {
const std::string _loggerCat = "TriangleSoup";
}
@@ -31,14 +33,14 @@ namespace {
namespace openspace {
namespace globebrowsing {
TriangleSoup::TriangleSoup(std::vector<unsigned int> elements,
Positions usePositions, TextureCoordinates useTextures, Normals useNormals)
TriangleSoup::TriangleSoup(std::vector<unsigned int> elements, Positions usePositions,
TextureCoordinates useTextures, Normals useNormals)
: _vaoID(0)
,_vertexBufferID(0)
,_elementBufferID(0)
,_useVertexPositions(usePositions)
,_useTextureCoordinates(useTextures)
,_useVertexNormals(useNormals)
, _vertexBufferID(0)
, _elementBufferID(0)
, _useVertexPositions(usePositions)
, _useTextureCoordinates(useTextures)
, _useVertexNormals(useNormals)
{
setElements(elements);
}
@@ -53,8 +55,7 @@ void TriangleSoup::setVertexPositions(std::vector<glm::vec4> positions) {
_useVertexPositions = true;
_gpuDataNeedUpdate = true;
_vertexData.resize(positions.size());
for (size_t i = 0; i < positions.size(); i++)
{
for (size_t i = 0; i < positions.size(); i++) {
_vertexData[i].position[0] = static_cast<GLfloat>(positions[i].x);
_vertexData[i].position[1] = static_cast<GLfloat>(positions[i].y);
_vertexData[i].position[2] = static_cast<GLfloat>(positions[i].z);
@@ -66,8 +67,7 @@ void TriangleSoup::setVertexTextureCoordinates(std::vector<glm::vec2> textures)
_useTextureCoordinates = true;
_gpuDataNeedUpdate = true;
_vertexData.resize(textures.size());
for (size_t i = 0; i < textures.size(); i++)
{
for (size_t i = 0; i < textures.size(); i++) {
_vertexData[i].texture[0] = static_cast<GLfloat>(textures[i].s);
_vertexData[i].texture[1] = static_cast<GLfloat>(textures[i].t);
}
@@ -77,8 +77,7 @@ void TriangleSoup::setVertexNormals(std::vector<glm::vec3> normals) {
_useVertexNormals = true;
_gpuDataNeedUpdate = true;
_vertexData.resize(normals.size());
for (size_t i = 0; i < normals.size(); i++)
{
for (size_t i = 0; i < normals.size(); i++) {
_vertexData[i].normal[0] = static_cast<GLfloat>(normals[i].x);
_vertexData[i].normal[1] = static_cast<GLfloat>(normals[i].y);
_vertexData[i].normal[2] = static_cast<GLfloat>(normals[i].z);
@@ -88,16 +87,16 @@ void TriangleSoup::setVertexNormals(std::vector<glm::vec3> normals) {
void TriangleSoup::setElements(std::vector<unsigned int> elements) {
_elementData.resize(elements.size());
_gpuDataNeedUpdate = true;
for (size_t i = 0; i < elements.size(); i++)
{
for (size_t i = 0; i < elements.size(); i++) {
_elementData[i] = static_cast<GLuint>(elements[i]);
}
}
bool TriangleSoup::updateDataOnGPU() {
// Create VAO
if (_vaoID == 0)
if (_vaoID == 0) {
glGenVertexArrays(1, &_vaoID);
}
// Create VBOs
if (_vertexBufferID == 0 && _vertexData.size() > 0) {
@@ -124,7 +123,8 @@ bool TriangleSoup::updateDataOnGPU() {
GL_ARRAY_BUFFER,
_vertexData.size() * sizeof(Vertex),
&_vertexData[0],
GL_STATIC_DRAW);
GL_STATIC_DRAW
);
// Positions at location 0
if (_useVertexPositions) {

View File

@@ -1,35 +1,33 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TRIANGLESOUP_H__
#define __TRIANGLESOUP_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TRIANGLESOUP_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TRIANGLESOUP_H__
#include <ghoul/glm.h>
#include <ghoul/misc/boolean.h>
#include <ghoul/opengl/ghoul_gl.h>
#include <ghoul/logging/logmanager.h>
#include <glm/glm.hpp>
#include <vector>
@@ -37,16 +35,15 @@ namespace openspace {
namespace globebrowsing {
/**
* Class to hold vertex data and handling OpenGL interfacing and rendering.
* A <code>TriangleSoup</code> has all data needed such as position buffer and normal
* buffer but all data is not necessarily needed for all purpouses so some vertex buffers
* such as normals can be disabled if not needed.
*/
* Class to hold vertex data and handling OpenGL interfacing and rendering.
* A <code>TriangleSoup</code> has all data needed such as position buffer and normal
* buffer but all data is not necessarily needed for all purpouses so some vertex buffers
* such as normals can be disabled if not needed.
*/
// TODO : Possibly render triangle strips in this class instead of triangles since
// that is faster
class TriangleSoup
{
class TriangleSoup {
public:
using Positions = ghoul::Boolean;
using TextureCoordinates = ghoul::Boolean;
@@ -93,8 +90,8 @@ protected:
// Vertex data
std::vector<Vertex> _vertexData;
std::vector<GLuint> _elementData;
private:
private:
bool updateDataOnGPU();
// GL handles
@@ -108,4 +105,4 @@ private:
} // namespace globebrowsing
} // namespace openspace
#endif // __TRIANGLESOUP_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TRIANGLESOUP_H__

View File

@@ -49,7 +49,7 @@ namespace globebrowsing {
virtual ~Job() { }
virtual void execute() = 0;
virtual std::shared_ptr<P> product() = 0;
virtual std::shared_ptr<P> product() const = 0;
};

View File

@@ -1,45 +1,32 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
// open space includes
#include <modules/globebrowsing/other/distanceswitch.h>
namespace {
const std::string _loggerCat = "DistanceSwitch";
}
namespace openspace {
namespace globebrowsing {
DistanceSwitch::DistanceSwitch(){
}
DistanceSwitch::~DistanceSwitch() {
}
bool DistanceSwitch::initialize() {
for (int i = 0; i < _renderables.size(); ++i) {
_renderables[i]->initialize();
@@ -54,9 +41,6 @@ bool DistanceSwitch::deinitialize() {
return true;
}
bool DistanceSwitch::isReady() const {
return true;
}
void DistanceSwitch::render(const RenderData& data) {
if (_maxDistances.size() == 0) {
@@ -85,9 +69,11 @@ void DistanceSwitch::update(const UpdateData& data) {
}
}
void DistanceSwitch::addSwitchValue(std::shared_ptr<Renderable> renderable, double maxDistance) {
void DistanceSwitch::addSwitchValue(std::shared_ptr<Renderable> renderable,
double maxDistance)
{
ghoul_assert(maxDistance > 0, "Renderable must have a positive maxDistance");
if (_maxDistances.size() > 0){
if (_maxDistances.size() > 0) {
ghoul_assert(maxDistance > _maxDistances.back(),
"Renderables must be inserted in ascending order wrt distance");
}
@@ -97,4 +83,3 @@ void DistanceSwitch::addSwitchValue(std::shared_ptr<Renderable> renderable, doub
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,75 +1,70 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __DISTANCESWITCH_H__
#define __DISTANCESWITCH_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_DISTANCESWITCH_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_DISTANCESWITCH_H__
// open space includes
#include <openspace/rendering/renderable.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/util/updatestructures.h>
#include <openspace/util/powerscaledcoordinate.h>
#include <openspace/util/powerscaledscalar.h>
#include <memory>
#include <vector>
namespace openspace {
struct RenderData;
struct UpdateData;
namespace globebrowsing {
/**
Selects a specific Renderable to be used for rendering, based on distance to the
camera
* Selects a specific Renderable to be used for rendering, based on distance to the
* camera
*/
class DistanceSwitch {
public:
DistanceSwitch();
virtual ~DistanceSwitch();
bool initialize();
bool deinitialize();
bool isReady() const;
/**
Picks the first Renderable with the associated maxDistance greater than the
current distance to the camera
* Picks the first Renderable with the associated maxDistance greater than the
* current distance to the camera
*/
void render(const RenderData& data);
void update(const UpdateData& data);
/**
Adds a new renderable (first argument) which may be rendered only if the distance
to the camera is less than maxDistance (second argument)
* Adds a new renderable (first argument) which may be rendered only if the distance
* to the camera is less than maxDistance (second argument)
*/
void addSwitchValue(std::shared_ptr<Renderable> renderable, double maxDistance);
private:
std::vector<std::shared_ptr<Renderable>> _renderables;
std::vector<double> _maxDistances;
};
} // namespace globebrowsing
} // openspace
#endif //__DISTANCESWITCH_H__
#endif //__OPENSPACE_MODULE_GLOBEBROWSING_DISTANCESWITCH_H__

View File

@@ -22,12 +22,101 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/other/statscollector.h>
#include <fstream>
#include <iomanip>
#include <string>
namespace openspace {
namespace globebrowsing {
StatsCollector::StatsCollector(const std::string& filename, int dumpEveryXRecord,
Enabled enabled, const std::string & delimiter)
: _filename(filename)
, _dumpEveryXRecord(dumpEveryXRecord)
, _recordsSinceLastDump(0)
, _enabled(enabled)
, _delimiter(delimiter)
, _hasWrittenHeader(false)
, i(TemplatedStatsCollector<long long>(_enabled, delimiter))
, d(TemplatedStatsCollector<double>(_enabled, delimiter))
{}
StatsCollector::~StatsCollector() {
dumpToDisk();
}
void StatsCollector::startNewRecord() {
if (_enabled) {
if (_dumpEveryXRecord && ++_recordsSinceLastDump >= _dumpEveryXRecord) {
dumpToDisk();
_recordsSinceLastDump = 0;
}
i.startNewRecord();
d.startNewRecord();
}
}
void StatsCollector::setEnabled(bool enabled) {
_enabled = enabled;
}
void StatsCollector::disable() {
_enabled = false;
}
void StatsCollector::enable() {
_enabled = true;
}
int StatsCollector::hasHeaders() {
return i.hasHeaders() || d.hasHeaders();
}
void StatsCollector::dumpToDisk() {
if (_enabled && hasHeaders()) {
if (!_hasWrittenHeader) {
writeHeader();
}
writeData();
}
}
void StatsCollector::writeHeader() {
std::ofstream ofs(_filename);
if (i.hasHeaders()) {
i.writeHeader(ofs);
if (d.hasHeaders()) {
ofs << _delimiter;
d.writeHeader(ofs);
}
}
else {
d.writeHeader(ofs);
}
_hasWrittenHeader = true;
ofs << std::endl;
ofs.close();
}
void StatsCollector::writeData() {
std::ofstream ofs(_filename, std::ofstream::out | std::ofstream::app);
ofs << std::setprecision(32);
while (i.hasRecordsToWrite() || d.hasRecordsToWrite()) {
if (i.hasHeaders() && d.hasHeaders()) {
i.writeNextRecord(ofs); ofs << _delimiter; d.writeNextRecord(ofs);
}
else {
i.writeNextRecord(ofs); d.writeNextRecord(ofs);
}
ofs << std::endl;
}
i.reset();
d.reset();
ofs.close();
}
} // namespace globebrowsing
} // namespace openspace
} // namespace openspace

View File

@@ -21,264 +21,103 @@
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __STATS_TRACKER_H__
#define __STATS_TRACKER_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_STATS_TRACKER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_STATS_TRACKER_H__
#include <ghoul/misc/boolean.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem>
#include <fstream>
#include <iomanip>
#include <set>
#include <unordered_map>
#include <vector>
#include <set>
#include <memory>
namespace openspace {
namespace globebrowsing {
template <typename T>
struct StatsRecord : public std::unordered_map<std::string, T> {
template <typename T>
using StatsRecord = std::unordered_map<std::string, T>;
};
template <typename T>
struct StatsCollection : public std::vector<StatsRecord<T>> {
std::set<std::string> keys;
};
template <typename T>
struct StatsCollection : public std::vector<StatsRecord<T>> {
std::set<std::string> keys;
};
template <typename T>
class TemplatedStatsCollector {
public:
TemplatedStatsCollector(bool& enabled, const std::string& delimiter);
template <typename T> class TemplatedStatsCollector{
public:
~TemplatedStatsCollector() = default;
TemplatedStatsCollector(bool& enabled, const std::string& delimiter)
: _enabled(enabled)
, _delimiter(delimiter)
, _writePos(0) { };
void startNewRecord();
~TemplatedStatsCollector() { };
T& operator[](const std::string& name);
void startNewRecord() {
if(_enabled)
_data.push_back(StatsRecord<T>());
}
T previous(const std::string& name);
T& operator[](const std::string& name) {
if (_enabled) {
_data.keys.insert(name);
return _data.back()[name];
}
else return _dummy;
}
bool hasHeaders();
T previous(const std::string& name) {
if (_data.size() > 1) {
return _data[_data.size() - 2][name];
}
return T();
}
bool hasRecordsToWrite();
bool hasHeaders() {
return _data.keys.size() > 0;
}
void reset();
bool hasRecordsToWrite() {
return _writePos < _data.size() - 1;
}
void writeHeader(std::ostream& os);
void reset() {
// copy last, i.e. current record
StatsRecord<T> lastRecord = _data.back();
_data.clear();
// add it again after cleared the vector
_data.push_back(lastRecord);
_writePos = 0;
}
void writeNextRecord(std::ostream& os);
void writeHeader(std::ostream& os) {
auto keyIt = _data.keys.begin();
os << *keyIt;
while (++keyIt != _data.keys.end()) {
os << _delimiter << *keyIt;
}
}
private:
StatsCollection<T> _data;
T _dummy; // used when disabled
bool& _enabled;
void writeNextRecord(std::ostream& os) {
if (hasRecordsToWrite()) {
// output line by line
StatsRecord<T>& record = _data[_writePos];
size_t _writePos;
std::string _delimiter;
};
// Access every key. Records with no entry will get a default value
auto keyIt = _data.keys.begin();
if (keyIt != _data.keys.end()) {
os << record[(*keyIt)];
while (++keyIt != _data.keys.end()) {
os << _delimiter << record[(*keyIt)];
}
}
class StatsCollector {
public:
StatsCollector() = delete;
_writePos++;
}
}
using Enabled = ghoul::Boolean;
private:
StatsCollector(const std::string& filename, int dumpEveryXRecord,
Enabled enabled = Enabled::Yes, const std::string& delimiter = ",");
~StatsCollector();
StatsCollection<T> _data;
T _dummy; // used when disabled
bool& _enabled;
void startNewRecord();
size_t _writePos;
std::string _delimiter;
};
void setEnabled(bool enabled);
class StatsCollector {
void disable();
public:
void enable();
StatsCollector() = delete;
int hasHeaders();
using Enabled = ghoul::Boolean;
void dumpToDisk();
StatsCollector(const std::string& filename, int dumpEveryXRecord, Enabled enabled = Enabled::Yes, const std::string& delimiter = ",")
: _filename(filename)
, _dumpEveryXRecord(dumpEveryXRecord)
, _recordsSinceLastDump(0)
, _enabled(enabled)
, _delimiter(delimiter)
, _hasWrittenHeader(false)
, i(TemplatedStatsCollector<long long>(_enabled, delimiter))
, d(TemplatedStatsCollector<double>(_enabled, delimiter))
{
TemplatedStatsCollector<long long> i;
TemplatedStatsCollector<double> d;
};
private:
void writeHeader();
~StatsCollector() {
dumpToDisk();
}
void startNewRecord() {
if (_enabled) {
if (_dumpEveryXRecord && ++_recordsSinceLastDump >= _dumpEveryXRecord) {
dumpToDisk();
_recordsSinceLastDump = 0;
}
void writeData();
i.startNewRecord();
d.startNewRecord();
}
}
std::string _filename;
std::string _delimiter;
void setEnabled(bool enabled){
_enabled = enabled;
}
int _dumpEveryXRecord;
int _recordsSinceLastDump;
void disable() {
_enabled = false;
}
void enable() {
_enabled = true;
}
int hasHeaders() {
return i.hasHeaders() || d.hasHeaders();
}
void dumpToDisk() {
if (_enabled && hasHeaders()) {
if (!_hasWrittenHeader) {
writeHeader();
}
writeData();
}
}
TemplatedStatsCollector<long long> i;
TemplatedStatsCollector<double> d;
private:
void writeHeader() {
std::ofstream ofs(_filename);
if (i.hasHeaders()) {
i.writeHeader(ofs);
if (d.hasHeaders()) {
ofs << _delimiter;
d.writeHeader(ofs);
}
}
else {
d.writeHeader(ofs);
}
_hasWrittenHeader = true;
ofs << std::endl;
ofs.close();
}
void writeData() {
std::ofstream ofs(_filename, std::ofstream::out | std::ofstream::app);
ofs << std::setprecision(32);
while (i.hasRecordsToWrite() || d.hasRecordsToWrite()) {
if (i.hasHeaders() && d.hasHeaders()) {
i.writeNextRecord(ofs); ofs << _delimiter; d.writeNextRecord(ofs);
}
else {
i.writeNextRecord(ofs); d.writeNextRecord(ofs);
}
ofs << std::endl;
}
i.reset(); d.reset();
ofs.close();
}
std::string _filename;
std::string _delimiter;
int _dumpEveryXRecord;
int _recordsSinceLastDump;
bool _enabled;
bool _hasWrittenHeader;
};
/*
template <typename T>
struct StatsCsvWriter {
StatsCsvWriter(const std::string& delimiter)
: _delimiter(delimiter) { };
virtual void write(const StatsCollection<T>& stats, const std::string& filename) {
std::ofstream ofs(filename);
// output headers
auto keyIt = stats.keys.begin();
ofs << *keyIt;
while (keyIt++ != stats.keys.end()) {
ofs << _delimiter << *keyIt;
}
ofs << std::endl;
// output line by line
for (const StatsRecord<T>& record : stats) {
// Access every key. Records with no entry will get a default value
auto keyIt = stats.keys.begin();
ofs << record[*keyIt];
while (keyIt++ != stats.keys.end()) {
ofs << _delimiter << record[*keyIt];
}
ofs << std::endl;
}
ofs.close();
}
private:
std::string _delimiter;
};
*/
bool _enabled;
bool _hasWrittenHeader;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __STATS_TRACKER_H__
#include "statscollector.inl"
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_STATS_TRACKER_H__

View File

@@ -0,0 +1,113 @@
#include "statscollector.h"
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
namespace openspace {
namespace globebrowsing {
template <typename T>
TemplatedStatsCollector<T>::TemplatedStatsCollector(bool& enabled,
const std::string& delimiter)
: _enabled(enabled)
, _delimiter(delimiter)
, _writePos(0)
{}
template <typename T>
void TemplatedStatsCollector<T>::startNewRecord() {
if (_enabled) {
_data.push_back(StatsRecord<T>());
}
}
template <typename T>
T& TemplatedStatsCollector<T>::operator[](const std::string& name) {
if (_enabled) {
_data.keys.insert(name);
return _data.back()[name];
}
else {
return _dummy;
}
}
template<typename T>
T TemplatedStatsCollector<T>::previous(const std::string& name) {
if (_data.size() > 1) {
return _data[_data.size() - 2][name];
}
return T();
}
template<typename T>
bool TemplatedStatsCollector<T>::hasHeaders() {
return _data.keys.size() > 0;
}
template<typename T>
bool TemplatedStatsCollector<T>::hasRecordsToWrite() {
return _writePos < _data.size() - 1;
}
template<typename T>
void TemplatedStatsCollector<T>::reset() {
// copy last, i.e. current record
StatsRecord<T> lastRecord = _data.back();
_data.clear();
// add it again after cleared the vector
_data.push_back(lastRecord);
_writePos = 0;
}
template<typename T>
void TemplatedStatsCollector<T>::writeHeader(std::ostream& os) {
auto keyIt = _data.keys.begin();
os << *keyIt;
while (++keyIt != _data.keys.end()) {
os << _delimiter << *keyIt;
}
}
template<typename T>
void TemplatedStatsCollector<T>::writeNextRecord(std::ostream& os) {
if (hasRecordsToWrite()) {
// output line by line
StatsRecord<T>& record = _data[_writePos];
// Access every key. Records with no entry will get a default value
auto keyIt = _data.keys.begin();
if (keyIt != _data.keys.end()) {
os << record[(*keyIt)];
while (++keyIt != _data.keys.end()) {
os << _delimiter << record[(*keyIt)];
}
}
_writePos++;
}
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -22,94 +22,82 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <memory>
#include <ostream>
#include <thread>
#include <queue>
#include <modules/globebrowsing/other/concurrentqueue.h>
#include <modules/globebrowsing/other/threadpool.h>
#include <ghoul/misc/assert.h>
#include <iostream>
namespace openspace {
namespace globebrowsing {
Worker::Worker(ThreadPool& pool)
: pool(pool)
{
Worker::Worker(ThreadPool& pool)
: pool(pool)
{}
void Worker::operator()() {
std::function<void()> task;
while (true) {
// acquire lock
{
std::unique_lock<std::mutex> lock(pool.queue_mutex);
// look for a work item
while (!pool.stop && pool.tasks.empty()) {
// if there are none wait for notification
pool.condition.wait(lock);
}
if (pool.stop) { // exit if the pool is stopped
return;
}
// get the task from the queue
task = pool.tasks.front();
pool.tasks.pop_front();
}// release lock
// execute the task
task();
}
}
void Worker::operator()() {
std::function<void()> task;
while (true) {
// acquire lock
{
std::unique_lock<std::mutex> lock(pool.queue_mutex);
// look for a work item
while (!pool.stop && pool.tasks.empty()) {
// if there are none wait for notification
pool.condition.wait(lock);
}
if (pool.stop) { // exit if the pool is stopped
return;
}
// get the task from the queue
task = pool.tasks.front();
pool.tasks.pop_front();
}// release lock
// execute the task
task();
}
ThreadPool::ThreadPool(size_t numThreads)
: stop(false)
{
for (size_t i = 0; i < numThreads; ++i) {
workers.push_back(std::thread(Worker(*this)));
}
}
ThreadPool::ThreadPool(size_t numThreads)
: stop(false)
{
for (size_t i = 0; i < numThreads; ++i) {
workers.push_back(std::thread(Worker(*this)));
}
// the destructor joins all threads
ThreadPool::~ThreadPool() {
// stop all threads
stop = true;
condition.notify_all();
// join them
for (size_t i = 0; i < workers.size(); ++i) {
workers[i].join();
}
}
// the destructor joins all threads
ThreadPool::~ThreadPool() {
// stop all threads
stop = true;
condition.notify_all();
// add new work item to the pool
void ThreadPool::enqueue(std::function<void()> f) {
{ // acquire lock
std::unique_lock<std::mutex> lock(queue_mutex);
// join them
for (size_t i = 0; i < workers.size(); ++i) {
workers[i].join();
}
}
// add the task
tasks.push_back(f);
} // release lock
// add new work item to the pool
void ThreadPool::enqueue(std::function<void()> f) {
{ // acquire lock
std::unique_lock<std::mutex> lock(queue_mutex);
// wake up one thread
condition.notify_one();
}
// add the task
tasks.push_back(f);
} // release lock
// wake up one thread
condition.notify_one();
}
void ThreadPool::clearTasks() {
{ // acquire lock
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.clear();
} // release lock
}
void ThreadPool::clearTasks() {
{ // acquire lock
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.clear();
} // release lock
}
} // namespace globebrowsing
} // namespace openspace
} // namespace openspace

View File

@@ -22,56 +22,52 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __THREAD_POOL_H__
#define __THREAD_POOL_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_THREAD_POOL_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_THREAD_POOL_H__
#include <glm/glm.hpp>
#include <memory>
#include <ostream>
#include <thread>
#include <functional>
#include <mutex>
#include <queue>
#include <modules/globebrowsing/other/concurrentqueue.h>
#include <ghoul/misc/assert.h>
#include <thread>
#include <vector>
// Implementatin based on http://progsch.net/wordpress/?p=81
namespace openspace {
namespace globebrowsing {
class ThreadPool;
class ThreadPool;
class Worker {
public:
Worker(ThreadPool& pool);
void operator()();
private:
ThreadPool& pool;
};
class Worker {
public:
Worker(ThreadPool& pool);
void operator()();
private:
ThreadPool& pool;
};
class ThreadPool {
public:
ThreadPool(size_t numThreads);
~ThreadPool();
class ThreadPool {
public:
ThreadPool(size_t numThreads);
~ThreadPool();
void enqueue(std::function<void()> f);
void clearTasks();
void enqueue(std::function<void()> f);
void clearTasks();
private:
friend class Worker;
private:
friend class Worker;
std::vector<std::thread> workers;
std::vector<std::thread> workers;
std::deque<std::function<void()>> tasks;
std::deque<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
bool stop;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __THREAD_POOL_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_THREAD_POOL_H__

View File

@@ -1,314 +1,297 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/tile/chunktile.h>
#include <modules/globebrowsing/rendering/chunkrenderer.h>
#include <modules/globebrowsing/rendering/layermanager.h>
// open space includes
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/rendering/renderengine.h>
// ghoul includes
#include <ghoul/misc/assert.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/opengl/textureunit.h>
// STL includes
#include <sstream>
#define _USE_MATH_DEFINES
#include <math.h>
#include <modules/globebrowsing/chunk/chunk.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <modules/globebrowsing/meshes/grid.h>
#include <modules/globebrowsing/rendering/layershadermanager.h>
namespace {
const std::string _loggerCat = "ChunkRenderer";
const char* keyFrame = "Frame";
const char* keyGeometry = "Geometry";
const char* keyShading = "PerformShading";
const std::string keyFrame = "Frame";
const std::string keyGeometry = "Geometry";
const std::string keyShading = "PerformShading";
const std::string keyBody = "Body";
const char* keyBody = "Body";
}
namespace openspace {
namespace globebrowsing {
ChunkRenderer::ChunkRenderer(
std::shared_ptr<Grid> grid,
std::shared_ptr<LayerManager> layerManager)
: _layerManager(layerManager)
, _grid(grid)
{
_globalLayerShaderManager = std::make_shared<LayerShaderManager>(
"GlobalChunkedLodPatch",
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_fs.glsl");
ChunkRenderer::ChunkRenderer(std::shared_ptr<Grid> grid,
std::shared_ptr<LayerManager> layerManager)
: _layerManager(layerManager)
, _grid(grid)
{
_globalLayerShaderManager = std::make_shared<LayerShaderManager>(
"GlobalChunkedLodPatch",
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_fs.glsl");
_localLayerShaderManager = std::make_shared<LayerShaderManager>(
"LocalChunkedLodPatch",
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_fs.glsl");
_localLayerShaderManager = std::make_shared<LayerShaderManager>(
"LocalChunkedLodPatch",
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_fs.glsl");
_globalGpuLayerManager = std::make_shared<GPULayerManager>();
_localGpuLayerManager = std::make_shared<GPULayerManager>();
_globalGpuLayerManager = std::make_shared<GPULayerManager>();
_localGpuLayerManager = std::make_shared<GPULayerManager>();
}
void ChunkRenderer::renderChunk(const Chunk& chunk, const RenderData& data) {
// A little arbitrary with 10 but it works
if (chunk.owner().debugProperties().onlyModelSpaceRendering || chunk.tileIndex().level < 10) {
renderChunkGlobally(chunk, data);
}
else {
renderChunkLocally(chunk, data);
}
}
void ChunkRenderer::update() {
// unused atm. Could be used for caching or precalculating
}
ghoul::opengl::ProgramObject* ChunkRenderer::getActivatedProgramWithTileData(
std::shared_ptr<LayerShaderManager> layeredShaderManager,
std::shared_ptr<GPULayerManager> gpuLayerManager,
const Chunk& chunk)
{
const TileIndex& tileIndex = chunk.tileIndex();
LayerShaderPreprocessingData layeredTexturePreprocessingData;
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; i++) {
LayerGroupPreprocessingData layeredTextureInfo;
auto layerGroup = _layerManager->layerGroup(i);
layeredTextureInfo.lastLayerIdx = layerGroup.activeLayers().size() - 1;
layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled();
layeredTexturePreprocessingData.layeredTextureInfo[i] = layeredTextureInfo;
}
const auto& generalProps = chunk.owner().generalProperties();
const auto& debugProps = chunk.owner().debugProperties();
auto& pairs = layeredTexturePreprocessingData.keyValuePairs;
pairs.push_back(std::make_pair("useAtmosphere",
std::to_string(generalProps.atmosphereEnabled)));
pairs.push_back(std::make_pair("performShading",
std::to_string(generalProps.performShading)));
pairs.push_back(std::make_pair("showChunkEdges",
std::to_string(debugProps.showChunkEdges)));
pairs.push_back(std::make_pair("showHeightResolution",
std::to_string(debugProps.showHeightResolution)));
pairs.push_back(std::make_pair("showHeightIntensities",
std::to_string(debugProps.showHeightIntensities)));
pairs.push_back(std::make_pair("defaultHeight",
std::to_string(Chunk::DEFAULT_HEIGHT)));
// Now the shader program can be accessed
ProgramObject* programObject =
layeredShaderManager->programObject(
layeredTexturePreprocessingData);
if (layeredShaderManager->updatedOnLastCall()) {
gpuLayerManager->bind(programObject, *_layerManager);
}
void ChunkRenderer::renderChunk(const Chunk& chunk, const RenderData& data) {
// A little arbitrary with 10 but it works
if (chunk.owner().debugProperties().onlyModelSpaceRendering || chunk.tileIndex().level < 10) {
renderChunkGlobally(chunk, data);
}
else {
renderChunkLocally(chunk, data);
}
// Activate the shader program
programObject->activate();
gpuLayerManager->setValue(programObject, *_layerManager, tileIndex);
// The length of the skirts is proportional to its size
// TODO: Skirt length should probably be proportional to the size reffered to by
// the chunk's most high resolution height map.
programObject->setUniform("skirtLength",
glm::min(static_cast<float>(chunk.surfacePatch().halfSize().lat * 1000000),
8700.0f));
programObject->setUniform("xSegments", _grid->xSegments());
if (chunk.owner().debugProperties().showHeightResolution) {
programObject->setUniform("vertexResolution",
glm::vec2(_grid->xSegments(), _grid->ySegments()));
}
return programObject;
}
void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data){
ProgramObject* programObject = getActivatedProgramWithTileData(
_globalLayerShaderManager,
_globalGpuLayerManager,
chunk);
if (programObject == nullptr) {
return;
}
void ChunkRenderer::update() {
// unused atm. Could be used for caching or precalculating
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
if (_layerManager->hasAnyBlendingLayersEnabled()) {
// Calculations are done in the reference frame of the globe. Hence, the
// camera position needs to be transformed with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
glm::dvec3 cameraPosition = glm::dvec3(
inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
ellipsoid.minimumRadius();
programObject->setUniform("cameraPosition", glm::vec3(cameraPosition));
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
}
ProgramObject* ChunkRenderer::getActivatedProgramWithTileData(
std::shared_ptr<LayerShaderManager> layeredShaderManager,
std::shared_ptr<GPULayerManager> gpuLayerManager,
const Chunk& chunk)
{
const TileIndex& tileIndex = chunk.tileIndex();
LayerShaderPreprocessingData layeredTexturePreprocessingData;
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; i++) {
LayerGroupPreprocessingData layeredTextureInfo;
auto layerGroup = _layerManager->layerGroup(i);
layeredTextureInfo.lastLayerIdx = layerGroup.activeLayers().size() - 1;
layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled();
layeredTexturePreprocessingData.layeredTextureInfo[i] = layeredTextureInfo;
}
// Calculate other uniform variables needed for rendering
Geodetic2 swCorner = chunk.surfacePatch().getCorner(Quad::SOUTH_WEST);
auto patchSize = chunk.surfacePatch().size();
const auto& generalProps = chunk.owner().generalProperties();
const auto& debugProps = chunk.owner().debugProperties();
auto& pairs = layeredTexturePreprocessingData.keyValuePairs;
pairs.push_back(std::make_pair("useAtmosphere",
std::to_string(generalProps.atmosphereEnabled)));
pairs.push_back(std::make_pair("performShading",
std::to_string(generalProps.performShading)));
pairs.push_back(std::make_pair("showChunkEdges",
std::to_string(debugProps.showChunkEdges)));
pairs.push_back(std::make_pair("showHeightResolution",
std::to_string(debugProps.showHeightResolution)));
pairs.push_back(std::make_pair("showHeightIntensities",
std::to_string(debugProps.showHeightIntensities)));
pairs.push_back(std::make_pair("defaultHeight",
std::to_string(Chunk::DEFAULT_HEIGHT)));
glm::dmat4 modelTransform = chunk.owner().modelTransform();
glm::dmat4 viewTransform = data.camera.combinedViewMatrix();
glm::mat4 modelViewTransform = glm::mat4(viewTransform * modelTransform);
glm::mat4 modelViewProjectionTransform = data.camera.projectionMatrix() *
modelViewTransform;
// Now the shader program can be accessed
ProgramObject* programObject =
layeredShaderManager->programObject(
layeredTexturePreprocessingData);
if (layeredShaderManager->updatedOnLastCall()) {
gpuLayerManager->bind(programObject, *_layerManager);
}
// Upload the uniform variables
programObject->setUniform(
"modelViewProjectionTransform", modelViewProjectionTransform);
programObject->setUniform("minLatLon", glm::vec2(swCorner.toLonLatVec2()));
programObject->setUniform("lonLatScalingFactor", glm::vec2(patchSize.toLonLatVec2()));
programObject->setUniform("radiiSquared", glm::vec3(ellipsoid.radiiSquared()));
// Activate the shader program
programObject->activate();
gpuLayerManager->setValue(programObject, *_layerManager, tileIndex);
// The length of the skirts is proportional to its size
// TODO: Skirt length should probably be proportional to the size reffered to by
// the chunk's most high resolution height map.
programObject->setUniform("skirtLength",
min(static_cast<float>(chunk.surfacePatch().halfSize().lat * 1000000),
8700.0f));
programObject->setUniform("xSegments", _grid->xSegments());
if (chunk.owner().debugProperties().showHeightResolution) {
programObject->setUniform("vertexResolution",
glm::vec2(_grid->xSegments(), _grid->ySegments()));
}
return programObject;
}
void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data){
ProgramObject* programObject = getActivatedProgramWithTileData(
_globalLayerShaderManager,
_globalGpuLayerManager,
chunk);
if (programObject == nullptr) {
return;
}
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
if (_layerManager->hasAnyBlendingLayersEnabled()) {
// Calculations are done in the reference frame of the globe. Hence, the
// camera position needs to be transformed with the inverse model matrix
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
glm::dvec3 cameraPosition = glm::dvec3(
inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
ellipsoid.minimumRadius();
programObject->setUniform("cameraPosition", vec3(cameraPosition));
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
}
// Calculate other uniform variables needed for rendering
Geodetic2 swCorner = chunk.surfacePatch().getCorner(Quad::SOUTH_WEST);
auto patchSize = chunk.surfacePatch().size();
dmat4 modelTransform = chunk.owner().modelTransform();
dmat4 viewTransform = data.camera.combinedViewMatrix();
mat4 modelViewTransform = mat4(viewTransform * modelTransform);
mat4 modelViewProjectionTransform = data.camera.projectionMatrix() *
modelViewTransform;
// Upload the uniform variables
if (_layerManager->layerGroup(
LayerManager::NightLayers).activeLayers().size() > 0 ||
_layerManager->layerGroup(
LayerManager::WaterMasks).activeLayers().size() > 0 ||
chunk.owner().generalProperties().atmosphereEnabled ||
chunk.owner().generalProperties().performShading) {
// This code temporary until real light sources can be implemented.
glm::vec3 directionToSunWorldSpace =
glm::normalize(-data.modelTransform.translation);
glm::vec3 directionToSunCameraSpace =
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
data.modelTransform.translation;
programObject->setUniform("modelViewTransform", modelViewTransform);
programObject->setUniform(
"modelViewProjectionTransform", modelViewProjectionTransform);
programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
programObject->setUniform("lonLatScalingFactor", vec2(patchSize.toLonLatVec2()));
programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared()));
"lightDirectionCameraSpace", -directionToSunCameraSpace);
}
if (_layerManager->layerGroup(
LayerManager::NightLayers).activeLayers().size() > 0 ||
_layerManager->layerGroup(
LayerManager::WaterMasks).activeLayers().size() > 0 ||
chunk.owner().generalProperties().atmosphereEnabled ||
chunk.owner().generalProperties().performShading) {
// This code temporary until real light sources can be implemented.
glm::vec3 directionToSunWorldSpace =
glm::normalize(-data.modelTransform.translation);
glm::vec3 directionToSunCameraSpace =
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
data.modelTransform.translation;
programObject->setUniform("modelViewTransform", modelViewTransform);
programObject->setUniform(
"lightDirectionCameraSpace", -directionToSunCameraSpace);
}
// OpenGL rendering settings
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// OpenGL rendering settings
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// render
_grid->geometry().drawUsingActiveProgram();
// render
_grid->geometry().drawUsingActiveProgram();
_globalGpuLayerManager->deactivate();
_globalGpuLayerManager->deactivate();
// disable shader
programObject->deactivate();
// disable shader
programObject->deactivate();
}
void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& data) {
ProgramObject* programObject = getActivatedProgramWithTileData(
_localLayerShaderManager,
_localGpuLayerManager,
chunk);
if (programObject == nullptr) {
return;
}
void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& data) {
ProgramObject* programObject = getActivatedProgramWithTileData(
_localLayerShaderManager,
_localGpuLayerManager,
chunk);
if (programObject == nullptr) {
return;
}
using namespace glm;
using namespace glm;
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
if (_layerManager->hasAnyBlendingLayersEnabled()) {
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
chunk.owner().ellipsoid().minimumRadius();
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
}
// Calculate other uniform variables needed for rendering
dmat4 modelTransform = chunk.owner().modelTransform();
dmat4 viewTransform = data.camera.combinedViewMatrix();
dmat4 modelViewTransform = viewTransform * modelTransform;
std::vector<std::string> cornerNames = { "p01", "p11", "p00", "p10" };
std::vector<Vec3> cornersCameraSpace(4);
for (int i = 0; i < 4; ++i) {
Quad q = (Quad)i;
Geodetic2 corner = chunk.surfacePatch().getCorner(q);
Vec3 cornerModelSpace = ellipsoid.cartesianSurfacePosition(corner);
Vec3 cornerCameraSpace =
Vec3(dmat4(modelViewTransform) * glm::dvec4(cornerModelSpace, 1));
cornersCameraSpace[i] = cornerCameraSpace;
programObject->setUniform(cornerNames[i], vec3(cornerCameraSpace));
}
// TODO: Patch normal can be calculated for all corners and then linearly
// interpolated on the GPU to avoid cracks for high altitudes.
vec3 patchNormalCameraSpace = normalize(
cross(cornersCameraSpace[Quad::SOUTH_EAST] -
cornersCameraSpace[Quad::SOUTH_WEST],
cornersCameraSpace[Quad::NORTH_EAST] -
cornersCameraSpace[Quad::SOUTH_WEST]));
programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace);
programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
if (_layerManager->layerGroup(
LayerManager::NightLayers).activeLayers().size() > 0 ||
_layerManager->layerGroup(
LayerManager::WaterMasks).activeLayers().size() > 0 ||
chunk.owner().generalProperties().atmosphereEnabled ||
chunk.owner().generalProperties().performShading)
{
glm::vec3 directionToSunWorldSpace =
glm::normalize(-data.modelTransform.translation);
glm::vec3 directionToSunCameraSpace =
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
data.modelTransform.translation;
programObject->setUniform(
"lightDirectionCameraSpace", -directionToSunCameraSpace);
}
// OpenGL rendering settings
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// render
_grid->geometry().drawUsingActiveProgram();
_localGpuLayerManager->deactivate();
// disable shader
programObject->deactivate();
if (_layerManager->hasAnyBlendingLayersEnabled()) {
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
chunk.owner().ellipsoid().minimumRadius();
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
}
// Calculate other uniform variables needed for rendering
dmat4 modelTransform = chunk.owner().modelTransform();
dmat4 viewTransform = data.camera.combinedViewMatrix();
dmat4 modelViewTransform = viewTransform * modelTransform;
std::vector<std::string> cornerNames = { "p01", "p11", "p00", "p10" };
std::vector<glm::dvec3> cornersCameraSpace(4);
for (int i = 0; i < 4; ++i) {
Quad q = (Quad)i;
Geodetic2 corner = chunk.surfacePatch().getCorner(q);
glm::dvec3 cornerModelSpace = ellipsoid.cartesianSurfacePosition(corner);
glm::dvec3 cornerCameraSpace =
glm::dvec3(dmat4(modelViewTransform) * glm::dvec4(cornerModelSpace, 1));
cornersCameraSpace[i] = cornerCameraSpace;
programObject->setUniform(cornerNames[i], vec3(cornerCameraSpace));
}
// TODO: Patch normal can be calculated for all corners and then linearly
// interpolated on the GPU to avoid cracks for high altitudes.
vec3 patchNormalCameraSpace = normalize(
cross(cornersCameraSpace[Quad::SOUTH_EAST] -
cornersCameraSpace[Quad::SOUTH_WEST],
cornersCameraSpace[Quad::NORTH_EAST] -
cornersCameraSpace[Quad::SOUTH_WEST]));
programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace);
programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
if (_layerManager->layerGroup(
LayerManager::NightLayers).activeLayers().size() > 0 ||
_layerManager->layerGroup(
LayerManager::WaterMasks).activeLayers().size() > 0 ||
chunk.owner().generalProperties().atmosphereEnabled ||
chunk.owner().generalProperties().performShading)
{
glm::vec3 directionToSunWorldSpace =
glm::normalize(-data.modelTransform.translation);
glm::vec3 directionToSunCameraSpace =
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
data.modelTransform.translation;
programObject->setUniform(
"lightDirectionCameraSpace", -directionToSunCameraSpace);
}
// OpenGL rendering settings
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// render
_grid->geometry().drawUsingActiveProgram();
_localGpuLayerManager->deactivate();
// disable shader
programObject->deactivate();
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,109 +1,103 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CHUNK_RENDERER_H__
#define __CHUNK_RENDERER_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_RENDERER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_RENDERER_H__
#include <memory>
#include <glm/glm.hpp>
// open space includes
#include <openspace/rendering/renderable.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
#include <modules/globebrowsing/meshes/grid.h>
#include <modules/globebrowsing/rendering/layershadermanager.h>
#include <modules/globebrowsing/tile/tileselector.h>
#include <modules/globebrowsing/chunk/chunknode.h>
#include <ghoul/opengl/textureunit.h>
namespace ghoul {
namespace opengl {
namespace ghoul { namespace opengl {
class ProgramObject;
}
}
} }
namespace openspace {
struct RenderData;
namespace globebrowsing {
class ChunkRenderer {
public:
ChunkRenderer(std::shared_ptr<Grid> grid,
std::shared_ptr<LayerManager> layerManager);
class Chunk;
class Grid;
class GPULayerManager;
class LayerManager;
class LayerShaderManager;
/**
Chooses to render a chunk either locally or globally depending on the chunklevel
of the <code>Chunk</code>.
*/
void renderChunk(const Chunk& chunk, const RenderData& data);
void update();
class ChunkRenderer {
public:
ChunkRenderer(std::shared_ptr<Grid> grid,
std::shared_ptr<LayerManager> layerManager);
private:
/**
Chunks can be rendered either globally or locally. Global rendering is performed
in the model space of the globe. With global rendering, the vertex positions
of a chunk are calculated in the vertex shader by transforming the geodetic
coordinates of the chunk to model space coordinates. We can only achieve floating
point precision by doing this which means that the camera too close to a global
tile will lead to jagging. We only render global chunks for lower chunk levels.
*/
void renderChunkGlobally(const Chunk& chunk, const RenderData& data);
/**
* Chooses to render a chunk either locally or globally depending on the chunklevel
* of the <code>Chunk</code>.
*/
void renderChunk(const Chunk& chunk, const RenderData& data);
void update();
/**
Local rendering of chunks are done using linear interpolation in camera space.
All four corner points of the chunk are calculated in double precision on the
CPU and transformed to camera space with double precision matrix transforms.
These positions can then be cast to floats and uploaded to the vertex shader.
The vertex shader rendering performs linear interpolation between the four
corner points to get the resulting chunk. This means that there will be an error
due to the curvature of the globe. The smaller the patch is (with higher chunk
levels) the better the approximation becomes. This is why we only render local
chunks for higher chunk levels.
*/
void renderChunkLocally(const Chunk& chunk, const RenderData& data);
private:
/**
* Chunks can be rendered either globally or locally. Global rendering is performed
* in the model space of the globe. With global rendering, the vertex positions
* of a chunk are calculated in the vertex shader by transforming the geodetic
* coordinates of the chunk to model space coordinates. We can only achieve floating
* point precision by doing this which means that the camera too close to a global
* tile will lead to jagging. We only render global chunks for lower chunk levels.
*/
void renderChunkGlobally(const Chunk& chunk, const RenderData& data);
/**
* Local rendering of chunks are done using linear interpolation in camera space.
* All four corner points of the chunk are calculated in double precision on the
* CPU and transformed to camera space with double precision matrix transforms.
* These positions can then be cast to floats and uploaded to the vertex shader.
* The vertex shader rendering performs linear interpolation between the four
* corner points to get the resulting chunk. This means that there will be an error
* due to the curvature of the globe. The smaller the patch is (with higher chunk
* levels) the better the approximation becomes. This is why we only render local
* chunks for higher chunk levels.
*/
void renderChunkLocally(const Chunk& chunk, const RenderData& data);
ProgramObject* getActivatedProgramWithTileData(
std::shared_ptr<LayerShaderManager> layeredShaderManager,
std::shared_ptr<GPULayerManager> gpuLayerManager,
const Chunk& chunk);
ghoul::opengl::ProgramObject* getActivatedProgramWithTileData(
std::shared_ptr<LayerShaderManager> layeredShaderManager,
std::shared_ptr<GPULayerManager> gpuLayerManager,
const Chunk& chunk);
// shared pointer to a grid which can be the same for all rendered chunks.
std::shared_ptr<Grid> _grid;
std::shared_ptr<LayerManager> _layerManager;
// shared pointer to a grid which can be the same for all rendered chunks.
std::shared_ptr<Grid> _grid;
std::shared_ptr<LayerManager> _layerManager;
// Two different shader programs. One for global and one for local rendering.
std::shared_ptr<LayerShaderManager> _globalLayerShaderManager;
std::shared_ptr<LayerShaderManager> _localLayerShaderManager;
// Two different shader programs. One for global and one for local rendering.
std::shared_ptr<LayerShaderManager> _globalLayerShaderManager;
std::shared_ptr<LayerShaderManager> _localLayerShaderManager;
// Layered texture uniforms are chached in the uniform ID handles.
std::shared_ptr<GPULayerManager> _globalGpuLayerManager;
std::shared_ptr<GPULayerManager> _localGpuLayerManager;
};
// Layered texture uniforms are chached in the uniform ID handles.
std::shared_ptr<GPULayerManager> _globalGpuLayerManager;
std::shared_ptr<GPULayerManager> _localGpuLayerManager;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __CHUNK_RENDERER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_RENDERER_H__

View File

@@ -1,56 +1,41 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tileIndex.h>
#include <modules/globebrowsing/tile/chunktile.h>
#include <modules/globebrowsing/tile/tileselector.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/rendering/gpulayermanager.h>
#include <modules/globebrowsing/rendering/layermanager.h>
#include <ghoul/misc/dictionary.h>
#include <ghoul/misc/assert.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/opengl/textureunit.h>
#include <ghoul/opengl/programobject.h>
#include <string>
#include <memory>
namespace {
const std::string _loggerCat = "GPULayerManager";
}
#include <modules/globebrowsing/tile/chunktile.h>
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/tile/tiledepthtransform.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
namespace openspace {
namespace globebrowsing {
// TileUvTransform
void GPUTileUvTransform::setValue(ProgramObject* programObject,
const TileUvTransform& tileUvTransform){
const TileUvTransform& tileUvTransform)
{
gpuUvOffset.setValue(programObject, tileUvTransform.uvOffset);
gpuUvScale.setValue(programObject, tileUvTransform.uvScale);
}
@@ -60,173 +45,185 @@ void GPUTileUvTransform::bind(ProgramObject* programObject, const std::string& n
gpuUvScale.bind(programObject, nameBase + "uvScale");
}
// TileDepthTransform
void GPUTileDepthTransform::setValue(ProgramObject* programObject,
const TileDepthTransform& depthTransform){
const TileDepthTransform& depthTransform)
{
gpuDepthOffset.setValue(programObject, depthTransform.depthOffset);
gpuDepthScale.setValue(programObject, depthTransform.depthScale);
}
void GPUTileDepthTransform::bind(ProgramObject* programObject, const std::string& nameBase){
void GPUTileDepthTransform::bind(ProgramObject* programObject,
const std::string& nameBase)
{
gpuDepthOffset.bind(programObject, nameBase + "depthOffset");
gpuDepthScale.bind(programObject, nameBase + "depthScale");
}
// ChunkTile
void GPUChunkTile::setValue(ProgramObject* programObject, const ChunkTile& chunkTile){
void GPUChunkTile::setValue(ProgramObject* programObject, const ChunkTile& chunkTile) {
gpuTexture.setValue(programObject, chunkTile.tile.texture);
gpuTileUvTransform.setValue(programObject, chunkTile.uvTransform);
}
void GPUChunkTile::bind(ProgramObject* programObject, const std::string& nameBase){
void GPUChunkTile::bind(ProgramObject* programObject, const std::string& nameBase) {
gpuTexture.bind(programObject, nameBase + "textureSampler");
gpuTileUvTransform.bind(programObject, nameBase + "uvTransform.");
}
void GPUChunkTile::deactivate(){
void GPUChunkTile::deactivate() {
gpuTexture.deactivate();
}
// ChunkTilePile
void GPUChunkTilePile::setValue(ProgramObject* programObject, const ChunkTilePile& chunkTilePile){
ghoul_assert(gpuChunkTiles.size() == chunkTilePile.chunkTiles.size(), "GPU and CPU ChunkTilePile must have same size!");
for (size_t i = 0; i < gpuChunkTiles.size(); ++i){
void GPUChunkTilePile::setValue(ProgramObject* programObject,
const ChunkTilePile& chunkTilePile)
{
ghoul_assert(
gpuChunkTiles.size() == chunkTilePile.chunkTiles.size(),
"GPU and CPU ChunkTilePile must have same size!"
);
for (size_t i = 0; i < gpuChunkTiles.size(); ++i) {
gpuChunkTiles[i].setValue(programObject, chunkTilePile.chunkTiles[i]);
}
}
void GPUChunkTilePile::bind(ProgramObject* programObject, const std::string& nameBase,
int pileSize){
int pileSize)
{
gpuChunkTiles.resize(pileSize);
for (size_t i = 0; i < gpuChunkTiles.size(); ++i){
for (size_t i = 0; i < gpuChunkTiles.size(); ++i) {
std::string nameExtension = "chunkTile" + std::to_string(i) + ".";
gpuChunkTiles[i].bind(programObject, nameBase + nameExtension);
}
}
void GPUChunkTilePile::deactivate(){
for (auto& gpuChunkTile : gpuChunkTiles){
void GPUChunkTilePile::deactivate() {
for (auto& gpuChunkTile : gpuChunkTiles) {
gpuChunkTile.deactivate();
}
}
void GPULayerRenderSettings::setValue(ProgramObject* programObject,
const LayerRenderSettings& layerSettings){
const LayerRenderSettings& layerSettings)
{
gpuOpacity.setValue(programObject, layerSettings.opacity.value());
gpuGamma.setValue(programObject, layerSettings.gamma.value());
gpuMultiplier.setValue(programObject, layerSettings.multiplier.value());
}
void GPULayerRenderSettings::bind(ProgramObject* programObject, const std::string& nameBase){
void GPULayerRenderSettings::bind(ProgramObject* programObject,
const std::string& nameBase)
{
gpuOpacity.bind(programObject, nameBase + "opacity");
gpuGamma.bind(programObject, nameBase + "gamma");
gpuMultiplier.bind(programObject, nameBase + "multiplier");
}
// Layer
void GPULayer::setValue(ProgramObject* programObject, const Layer& layer,
const TileIndex& tileIndex, int pileSize){
const TileIndex& tileIndex, int pileSize)
{
ChunkTilePile chunkTilePile = layer.getChunkTilePile(tileIndex, pileSize);
gpuChunkTilePile.setValue(programObject, chunkTilePile);
gpuRenderSettings.setValue(programObject, layer.renderSettings());
}
void GPULayer::bind(ProgramObject* programObject, const Layer& layer,
const std::string& nameBase, int pileSize){
const std::string& nameBase, int pileSize)
{
gpuChunkTilePile.bind(programObject, nameBase + "pile.", pileSize);
gpuRenderSettings.bind(programObject, nameBase + "settings.");
}
void GPULayer::deactivate(){
void GPULayer::deactivate() {
gpuChunkTilePile.deactivate();
}
// Override behavior for HeightLayer
void GPUHeightLayer::setValue(ProgramObject* programObject, const Layer& layer,
const TileIndex& tileIndex, int pileSize){
const TileIndex& tileIndex, int pileSize)
{
GPULayer::setValue(programObject, layer, tileIndex, pileSize);
gpuDepthTransform.setValue(programObject, layer.tileProvider()->depthTransform());
}
void GPUHeightLayer::bind(ProgramObject* programObject, const Layer& layer, const std::string& nameBase, int pileSize){
void GPUHeightLayer::bind(ProgramObject* programObject, const Layer& layer,
const std::string& nameBase, int pileSize)
{
GPULayer::bind(programObject, layer, nameBase, pileSize);
gpuDepthTransform.bind(programObject, nameBase + "depthTransform.");
}
// LayerGroup
void GPULayerGroup::setValue(ProgramObject* programObject, const LayerGroup& layerGroup,
const TileIndex& tileIndex){
const TileIndex& tileIndex)
{
auto& activeLayers = layerGroup.activeLayers();
ghoul_assert(activeLayers.size() == gpuActiveLayers.size(), "GPU and CPU active layers must have same size!");
for (int i = 0; i < activeLayers.size(); ++i){
gpuActiveLayers[i]->setValue(programObject, *activeLayers[i], tileIndex, layerGroup.pileSize());
ghoul_assert(
activeLayers.size() == gpuActiveLayers.size(),
"GPU and CPU active layers must have same size!"
);
for (int i = 0; i < activeLayers.size(); ++i) {
gpuActiveLayers[i]->setValue(
programObject,
*activeLayers[i],
tileIndex,
layerGroup.pileSize()
);
}
}
void GPULayerGroup::bind(ProgramObject* programObject, const LayerGroup& layerGroup,
const std::string& nameBase, int category){
const std::string& nameBase, int category)
{
auto activeLayers = layerGroup.activeLayers();
gpuActiveLayers.resize(activeLayers.size());
int pileSize = layerGroup.pileSize();
for (size_t i = 0; i < gpuActiveLayers.size(); ++i){
for (size_t i = 0; i < gpuActiveLayers.size(); ++i) {
// should maybe a proper GPULayer factory
gpuActiveLayers[i] = category == LayerManager::HeightLayers ?
gpuActiveLayers[i] = (category == LayerManager::HeightLayers) ?
std::make_unique<GPUHeightLayer>() :
std::make_unique<GPULayer>();
std::string nameExtension = "[" + std::to_string(i) + "].";
gpuActiveLayers[i]->bind(programObject, *activeLayers[i], nameBase + nameExtension, pileSize);
gpuActiveLayers[i]->bind(
programObject,
*activeLayers[i],
nameBase + nameExtension,
pileSize
);
}
}
void GPULayerGroup::deactivate(){
for (size_t i = 0; i < gpuActiveLayers.size(); ++i){
void GPULayerGroup::deactivate() {
for (size_t i = 0; i < gpuActiveLayers.size(); ++i) {
gpuActiveLayers[i]->deactivate();
}
}
// LayerManager
void GPULayerManager::setValue(ProgramObject* programObject, const LayerManager& layerManager,
const TileIndex& tileIndex){
void GPULayerManager::setValue(ProgramObject* programObject,
const LayerManager& layerManager,
const TileIndex& tileIndex)
{
auto layerGroups = layerManager.layerGroups();
for (size_t i = 0; i < layerGroups.size(); ++i){
for (size_t i = 0; i < layerGroups.size(); ++i) {
gpuLayerGroups[i]->setValue(programObject, *layerGroups[i], tileIndex);
}
}
void GPULayerManager::bind(ProgramObject* programObject, const LayerManager& layerManager){
void GPULayerManager::bind(ProgramObject* programObject, const LayerManager& layerManager)
{
auto layerGroups = layerManager.layerGroups();
if(gpuLayerGroups.size() != layerGroups.size()){
if (gpuLayerGroups.size() != layerGroups.size()) {
gpuLayerGroups.resize(layerGroups.size());
for(auto& gpuLayerGroup : gpuLayerGroups){
for (auto& gpuLayerGroup : gpuLayerGroups){
gpuLayerGroup = std::make_unique<GPULayerGroup>();
}
}
for (size_t i = 0; i < layerGroups.size(); ++i){
for (size_t i = 0; i < layerGroups.size(); ++i) {
std::string nameBase = LayerManager::LAYER_GROUP_NAMES[i];
gpuLayerGroups[i]->bind(programObject, *layerGroups[i], nameBase, i);
}
}
void GPULayerManager::deactivate(){
for (size_t i = 0; i < gpuLayerGroups.size(); ++i){
void GPULayerManager::deactivate() {
for (size_t i = 0; i < gpuLayerGroups.size(); ++i) {
gpuLayerGroups[i]->deactivate();
}
}

View File

@@ -1,57 +1,54 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __GPU_LAYER_MANAGER_H__
#define __GPU_LAYER_MANAGER_H__
#include <modules/globebrowsing/tile/tileindex.h>
#include <modules/globebrowsing/tile/chunktile.h>
#include <modules/globebrowsing/rendering/layermanager.h>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_GPU_LAYER_MANAGER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_GPU_LAYER_MANAGER_H__
#include <openspace/util/gpudata.h>
#include <glm/glm.hpp>
#include <string>
#include <vector>
namespace ghoul{
namespace opengl{
class ProgramObject;
}//namespace opengl
}//namespace ghoul
namespace ghoul { namespace opengl {
class ProgramObject;
}}
namespace openspace {
namespace globebrowsing {
using namespace ghoul::opengl;
struct ChunkTile;
struct ChunkTilePile;
class Layer;
class LayerRenderSettings;
struct TileDepthTransform;
struct TileIndex;
struct TileUvTransform;
/**
* Manages a GPU representation of a <code>TileUvTransform</code>
*/
class GPUTileUvTransform {
public:
/**
* Sets the value of <code>TileUvTransform</code> to its corresponding
* GPU struct. OBS! Users must ensure bind has been
@@ -319,4 +316,5 @@ private:
} // namespace globebrowsing
} // namespace openspace
#endif // __GPU_LAYER_MANAGER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_GPU_LAYER_MANAGER_H__

View File

@@ -1,226 +1,194 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/util/factorymanager.h>
#include <openspace/properties/scalarproperty.h>
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/rendering/layermanager.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/tileselector.h>
#include <ghoul/logging/logmanager.h>
#include "cpl_minixml.h"
namespace {
const std::string _loggerCat = "LayerManager";
}
namespace openspace {
namespace globebrowsing {
LayerRenderSettings::LayerRenderSettings()
: opacity(properties::FloatProperty("opacity", "opacity", 1, 0, 1))
, gamma(properties::FloatProperty("gamma", "gamma", 1, 0, 5))
, multiplier(properties::FloatProperty("multiplier", "multiplier", 1, 0, 20))
{
setName("settings");
addProperty(opacity);
addProperty(gamma);
addProperty(multiplier);
}
LayerRenderSettings::LayerRenderSettings()
: opacity(properties::FloatProperty("opacity", "opacity", 1.f, 0.f, 1.f))
, gamma(properties::FloatProperty("gamma", "gamma", 1, 0, 5))
, multiplier(properties::FloatProperty("multiplier", "multiplier", 1.f, 0.f, 20.f))
{
setName("settings");
addProperty(opacity);
addProperty(gamma);
addProperty(multiplier);
}
//////////////////////////////////////////////////////////////////////////////////////
// Layer //
//////////////////////////////////////////////////////////////////////////////////////
Layer::Layer(const ghoul::Dictionary& layerDict)
: _enabled(properties::BoolProperty("enabled", "enabled", false))
{
std::string layerName = "error!";
layerDict.getValue("Name", layerName);
setName(layerName);
Layer::Layer(const ghoul::Dictionary& layerDict)
: _enabled(properties::BoolProperty("enabled", "enabled", false))
{
std::string layerName = "error!";
layerDict.getValue("Name", layerName);
setName(layerName);
_tileProvider = std::shared_ptr<TileProvider>(
TileProvider::createFromDictionary(layerDict));
_tileProvider = std::shared_ptr<TileProvider>(
TileProvider::createFromDictionary(layerDict));
// Something else went wrong and no exception was thrown
if (_tileProvider == nullptr) {
throw ghoul::RuntimeError("Unable to create TileProvider '" + name() + "'");
// Something else went wrong and no exception was thrown
if (_tileProvider == nullptr) {
throw ghoul::RuntimeError("Unable to create TileProvider '" + name() + "'");
}
bool enabled = false; // defaults to false if unspecified
layerDict.getValue("Enabled", enabled);
_enabled.setValue(enabled);
addProperty(_enabled);
addPropertySubOwner(_renderSettings);
}
ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const {
return std::move(_tileProvider->getChunkTilePile(tileIndex, pileSize));
}
LayerGroup::LayerGroup(std::string name)
: _levelBlendingEnabled("blendTileLevels", "blend tile levels", true)
{
setName(std::move(name));
addProperty(_levelBlendingEnabled);
}
LayerGroup::LayerGroup(std::string name, const ghoul::Dictionary& dict)
: LayerGroup(std::move(name))
{
for (size_t i = 0; i < dict.size(); i++) {
std::string dictKey = std::to_string(i + 1);
ghoul::Dictionary layerDict = dict.value<ghoul::Dictionary>(dictKey);
try {
_layers.push_back(std::make_shared<Layer>(layerDict));
}
bool enabled = false; // defaults to false if unspecified
layerDict.getValue("Enabled", enabled);
_enabled.setValue(enabled);
addProperty(_enabled);
addPropertySubOwner(_renderSettings);
}
Layer::~Layer(){
}
ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const {
return std::move(_tileProvider->getChunkTilePile(tileIndex, pileSize));
}
//////////////////////////////////////////////////////////////////////////////////////
// Layer Group //
//////////////////////////////////////////////////////////////////////////////////////
LayerGroup::LayerGroup(std::string name)
: _levelBlendingEnabled("blendTileLevels", "blend tile levels", true)
{
setName(name);
addProperty(_levelBlendingEnabled);
}
LayerGroup::LayerGroup(std::string name, const ghoul::Dictionary& dict)
: LayerGroup(name)
{
for (size_t i = 0; i < dict.size(); i++) {
std::string dictKey = std::to_string(i + 1);
ghoul::Dictionary layerDict = dict.value<ghoul::Dictionary>(dictKey);
try {
_layers.push_back(std::make_shared<Layer>(layerDict));
}
catch (const ghoul::RuntimeError& e) {
LERROR(e.what());
continue;
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
continue;
}
//_layers.push_back(std::make_shared<Layer>(layerDict));
}
for(auto layer : _layers){
addPropertySubOwner(layer.get());
for (const auto& layer : _layers) {
addPropertySubOwner(layer.get());
}
}
void LayerGroup::update() {
_activeLayers.clear();
for (const auto& layer : _layers) {
if (layer->enabled()) {
layer->tileProvider()->update();
_activeLayers.push_back(layer);
}
}
}
void LayerGroup::update() {
_activeLayers.clear();
const std::vector<std::shared_ptr<Layer>>& LayerGroup::layers() const {
return _layers;
}
for (auto layer : _layers) {
if (layer->enabled()) {
layer->tileProvider()->update();
_activeLayers.push_back(layer);
}
}
}
const std::vector<std::shared_ptr<Layer>>& LayerGroup::layers() const {
return _layers;
}
const std::vector<std::shared_ptr<Layer>>& LayerGroup::activeLayers() const {
return _activeLayers;
}
int LayerGroup::pileSize() const{
return _levelBlendingEnabled.value() ? 3 : 1;
}
//////////////////////////////////////////////////////////////////////////////////////
// LayerManager //
//////////////////////////////////////////////////////////////////////////////////////
const std::string LayerManager::LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = {
"HeightLayers",
"ColorLayers",
"ColorOverlays",
"GrayScaleLayers",
"GrayScaleColorOverlays",
"NightLayers",
"WaterMasks",
};
LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) {
setName("Layers");
if (NUM_LAYER_GROUPS != layerGroupsDict.size()) {
throw ghoul::RuntimeError(
"Number of Layer Groups must be equal to " + NUM_LAYER_GROUPS);
}
// Create all the categories of tile providers
for (size_t i = 0; i < layerGroupsDict.size(); i++) {
std::string groupName = LayerManager::LAYER_GROUP_NAMES[i];
ghoul::Dictionary layerGroupDict =
layerGroupsDict.value<ghoul::Dictionary>(groupName);
_layerGroups.push_back(
std::make_shared<LayerGroup>(groupName, layerGroupDict));
}
for(auto layerGroup : _layerGroups){
addPropertySubOwner(layerGroup.get());
}
}
LayerManager::~LayerManager(){
}
const LayerGroup& LayerManager::layerGroup(size_t groupId) {
return *_layerGroups[groupId];
}
const LayerGroup& LayerManager::layerGroup(LayerGroupId groupId) {
return *_layerGroups[groupId];
}
bool LayerManager::hasAnyBlendingLayersEnabled() const {
for (const auto& layerGroup : _layerGroups){
if (layerGroup->layerBlendingEnabled() &&
layerGroup->activeLayers().size() > 0){
return true;
}
}
return false;
}
const std::vector<std::shared_ptr<LayerGroup>>& LayerManager::layerGroups() const {
return _layerGroups;
}
void LayerManager::update() {
for (auto& layerGroup : _layerGroups) {
layerGroup->update();
}
}
void LayerManager::reset(bool includeDisabled) {
for (auto& layerGroup : _layerGroups) {
for (auto layer : layerGroup->layers()) {
if (layer->enabled() || includeDisabled) {
layer->tileProvider()->reset();
}
const std::vector<std::shared_ptr<Layer>>& LayerGroup::activeLayers() const {
return _activeLayers;
}
int LayerGroup::pileSize() const{
return _levelBlendingEnabled.value() ? 3 : 1;
}
const char* LayerManager::LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = {
"HeightLayers",
"ColorLayers",
"ColorOverlays",
"GrayScaleLayers",
"GrayScaleColorOverlays",
"NightLayers",
"WaterMasks"
};
LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) {
setName("Layers");
if (NUM_LAYER_GROUPS != layerGroupsDict.size()) {
throw ghoul::RuntimeError(
"Number of Layer Groups must be equal to " + NUM_LAYER_GROUPS);
}
// Create all the categories of tile providers
for (size_t i = 0; i < layerGroupsDict.size(); i++) {
std::string groupName = LayerManager::LAYER_GROUP_NAMES[i];
ghoul::Dictionary layerGroupDict =
layerGroupsDict.value<ghoul::Dictionary>(groupName);
_layerGroups.push_back(
std::make_shared<LayerGroup>(groupName, layerGroupDict));
}
for (const auto& layerGroup : _layerGroups) {
addPropertySubOwner(layerGroup.get());
}
}
const LayerGroup& LayerManager::layerGroup(size_t groupId) {
return *_layerGroups[groupId];
}
const LayerGroup& LayerManager::layerGroup(LayerGroupId groupId) {
return *_layerGroups[groupId];
}
bool LayerManager::hasAnyBlendingLayersEnabled() const {
for (const auto& layerGroup : _layerGroups) {
if (layerGroup->layerBlendingEnabled() && layerGroup->activeLayers().size() > 0) {
return true;
}
}
return false;
}
const std::vector<std::shared_ptr<LayerGroup>>& LayerManager::layerGroups() const {
return _layerGroups;
}
void LayerManager::update() {
for (auto& layerGroup : _layerGroups) {
layerGroup->update();
}
}
void LayerManager::reset(bool includeDisabled) {
for (auto& layerGroup : _layerGroups) {
for (auto layer : layerGroup->layers()) {
if (layer->enabled() || includeDisabled) {
layer->tileProvider()->reset();
}
}
}
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,137 +1,132 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __LAYERMANAGER_H__
#define __LAYERMANAGER_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_LAYERMANAGER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_LAYERMANAGER_H__
#include <openspace/properties/propertyowner.h>
#include <modules/globebrowsing/tile/chunktile.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/scalarproperty.h>
#include <openspace/util/gpudata.h>
#include <memory>
#include <vector>
#include <string>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
namespace openspace {
namespace globebrowsing {
class TileProvider;
class TileProvider;
struct LayerRenderSettings : public properties::PropertyOwner{
LayerRenderSettings();
properties::FloatProperty opacity;
properties::FloatProperty gamma;
properties::FloatProperty multiplier;
struct LayerRenderSettings : public properties::PropertyOwner {
LayerRenderSettings();
properties::FloatProperty opacity;
properties::FloatProperty gamma;
properties::FloatProperty multiplier;
};
/**
* Simple struct which is used to enable/disable <code>TileProvider</code>
* and associate is with a name. It also holds layer specific information
* which is used in rendering of layer.
*/
class Layer : public properties::PropertyOwner {
public:
Layer(const ghoul::Dictionary& layerDict);
ChunkTilePile getChunkTilePile(const TileIndex& tileIndex, int pileSize) const;
bool enabled() const { return _enabled.value(); }
TileProvider* tileProvider() const { return _tileProvider.get(); }
const LayerRenderSettings& renderSettings() const { return _renderSettings; }
private:
properties::BoolProperty _enabled;
std::shared_ptr<TileProvider> _tileProvider;
LayerRenderSettings _renderSettings;
};
/**
* Convenience class for dealing with multiple <code>Layer</code>s.
*/
struct LayerGroup : public properties::PropertyOwner {
LayerGroup(std::string name);
LayerGroup(std::string name, const ghoul::Dictionary& dict);
/// Updates all layers tile providers within this group
void update();
/// @returns const vector of all layers
const std::vector<std::shared_ptr<Layer>>& layers() const;
/// @returns const vector of all active layers
const std::vector<std::shared_ptr<Layer>>& activeLayers() const;
/// @returns the size of the pile to be used in rendering of this layer
int pileSize() const;
bool layerBlendingEnabled() const { return _levelBlendingEnabled.value(); }
private:
std::vector<std::shared_ptr<Layer>> _layers;
std::vector<std::shared_ptr<Layer>> _activeLayers;
properties::BoolProperty _levelBlendingEnabled;
};
/**
* Manages multiple LayerGroups.
*/
class LayerManager : public properties::PropertyOwner {
public:
static const size_t NUM_LAYER_GROUPS = 7;
static const char* LAYER_GROUP_NAMES[NUM_LAYER_GROUPS];
static enum LayerGroupId {
HeightLayers,
ColorLayers,
ColorOverlays,
GrayScaleLayers,
GrayScaleColorOverlays,
NightLayers,
WaterMasks,
};
/**
* Simple struct which is used to enable/disable <code>TileProvider</code>
* and associate is with a name. It also holds layer specific information
* which is used in rendering of layer.
*/
class Layer : public properties::PropertyOwner {
public:
Layer(const ghoul::Dictionary& layerDict);
~Layer();
LayerManager(const ghoul::Dictionary& textureCategoriesDictionary);
ChunkTilePile getChunkTilePile(const TileIndex& tileIndex, int pileSize) const;
const LayerGroup& layerGroup(size_t groupId);
const LayerGroup& layerGroup(LayerGroupId);
bool enabled() const { return _enabled.value(); }
TileProvider* tileProvider() const { return _tileProvider.get(); }
const LayerRenderSettings& renderSettings() const { return _renderSettings; }
bool hasAnyBlendingLayersEnabled() const;
private:
properties::BoolProperty _enabled;
std::shared_ptr<TileProvider> _tileProvider;
LayerRenderSettings _renderSettings;
};
const std::vector<std::shared_ptr<LayerGroup>>& layerGroups() const;
/**
* Convenience class for dealing with multiple <code>Layer</code>s.
*/
struct LayerGroup : public properties::PropertyOwner {
LayerGroup(std::string name);
LayerGroup(std::string name, const ghoul::Dictionary& dict);
void update();
void reset(bool includingDisabled = false);
/// Updates all layers tile providers within this group
void update();
/// @returns const vector of all layers
const std::vector<std::shared_ptr<Layer>>& layers() const;
/// @returns const vector of all active layers
const std::vector<std::shared_ptr<Layer>>& activeLayers() const;
/// @returns the size of the pile to be used in rendering of this layer
int pileSize() const;
bool layerBlendingEnabled() const { return _levelBlendingEnabled.value(); }
private:
std::vector<std::shared_ptr<Layer>> _layers;
std::vector<std::shared_ptr<Layer>> _activeLayers;
properties::BoolProperty _levelBlendingEnabled;
};
/**
* Manages multiple LayerGroups.
*/
class LayerManager : public properties::PropertyOwner {
public:
static const size_t NUM_LAYER_GROUPS = 7;
static const std::string LAYER_GROUP_NAMES[NUM_LAYER_GROUPS];
static enum LayerGroupId{
HeightLayers,
ColorLayers,
ColorOverlays,
GrayScaleLayers,
GrayScaleColorOverlays,
NightLayers,
WaterMasks,
};
LayerManager(const ghoul::Dictionary& textureCategoriesDictionary);
~LayerManager();
const LayerGroup& layerGroup(size_t groupId);
const LayerGroup& layerGroup(LayerGroupId);
bool hasAnyBlendingLayersEnabled() const;
const std::vector<std::shared_ptr<LayerGroup>>& layerGroups() const;
void update();
void reset(bool includingDisabled = false);
private:
std::vector<std::shared_ptr<LayerGroup>> _layerGroups;
};
private:
std::vector<std::shared_ptr<LayerGroup>> _layerGroups;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __LAYERMANAGER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_LAYERMANAGER_H__

View File

@@ -1,73 +1,57 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/assert.h>
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/asynctilereader.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/tiledataset.h>
#include <modules/globebrowsing/tile/tilediskcache.h>
#include <modules/globebrowsing/geometry/angle.h>
namespace {
const std::string _loggerCat = "AsyncTextureDataProvider";
}
namespace openspace {
namespace globebrowsing {
void TileLoadJob::execute() {
_rawTile = _tileDataset->readTileData(_chunkIndex);
}
void TileLoadJob::execute() {
_rawTile = _tileDataset->readTileData(_chunkIndex);
}
DiskCachedTileLoadJob::DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc, CacheMode m)
: TileLoadJob(textureDataProvider, tileIndex)
, _tileDiskCache(tdc)
, _mode(m)
{
std::shared_ptr<RawTile> TileLoadJob::product() const {
return _rawTile;
}
}
DiskCachedTileLoadJob::DiskCachedTileLoadJob(
std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex,
std::shared_ptr<TileDiskCache> tdc,
CacheMode m)
: TileLoadJob(textureDataProvider, tileIndex)
, _tileDiskCache(tdc)
, _mode(m)
{}
DiskCachedTileLoadJob::DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc, const std::string cacheMode)
: TileLoadJob(textureDataProvider, tileIndex)
, _tileDiskCache(tdc)
{
if (cacheMode == "Disabled") _mode = CacheMode::Disabled;
else if (cacheMode == "ReadOnly") _mode = CacheMode::ReadOnly;
else if (cacheMode == "ReadAndWrite") _mode = CacheMode::ReadAndWrite;
else if (cacheMode == "WriteOnly") _mode = CacheMode::WriteOnly;
else if (cacheMode == "CacheHitsOnly") _mode = CacheMode::CacheHitsOnly;
}
void DiskCachedTileLoadJob::execute() {
_rawTile = nullptr;
void DiskCachedTileLoadJob::execute() {
_rawTile = nullptr;
switch (_mode) {
switch (_mode) {
case CacheMode::Disabled:
_rawTile = _tileDataset->readTileData(_chunkIndex);
break;
@@ -100,72 +84,68 @@ namespace globebrowsing {
_rawTile = std::make_shared<RawTile>(res);
}
break;
}
}
}
AsyncTileDataProvider::AsyncTileDataProvider(
std::shared_ptr<TileDataset> tileDataset,
std::shared_ptr<ThreadPool> pool)
: _tileDataset(tileDataset)
, _concurrentJobManager(pool)
{}
AsyncTileDataProvider::AsyncTileDataProvider(std::shared_ptr<TileDataset> tileDataset,
std::shared_ptr<ThreadPool> pool)
: _tileDataset(tileDataset)
, _concurrentJobManager(pool)
{}
AsyncTileDataProvider::~AsyncTileDataProvider()
{}
std::shared_ptr<TileDataset> AsyncTileDataProvider::getTextureDataProvider() const {
return _tileDataset;
}
std::shared_ptr<TileDataset> AsyncTileDataProvider::getTextureDataProvider() const {
return _tileDataset;
bool AsyncTileDataProvider::enqueueTileIO(const TileIndex& tileIndex) {
if (satisfiesEnqueueCriteria(tileIndex)) {
auto job = std::make_shared<TileLoadJob>(_tileDataset, tileIndex);
//auto job = std::make_shared<DiskCachedTileLoadJob>(_tileDataset, tileIndex, tileDiskCache, "ReadAndWrite");
_concurrentJobManager.enqueueJob(job);
_enqueuedTileRequests[tileIndex.hashKey()] = tileIndex;
return true;
}
return false;
}
bool AsyncTileDataProvider::enqueueTileIO(const TileIndex& tileIndex) {
if (satisfiesEnqueueCriteria(tileIndex)) {
auto job = std::make_shared<TileLoadJob>(_tileDataset, tileIndex);
//auto job = std::make_shared<DiskCachedTileLoadJob>(_tileDataset, tileIndex, tileDiskCache, "ReadAndWrite");
_concurrentJobManager.enqueueJob(job);
_enqueuedTileRequests[tileIndex.hashKey()] = tileIndex;
return true;
}
return false;
std::vector<std::shared_ptr<RawTile>> AsyncTileDataProvider::getRawTiles() {
std::vector<std::shared_ptr<RawTile>> readyResults;
while (_concurrentJobManager.numFinishedJobs() > 0) {
readyResults.push_back(_concurrentJobManager.popFinishedJob()->product());
}
return readyResults;
}
std::vector<std::shared_ptr<RawTile>> AsyncTileDataProvider::getRawTiles() {
std::vector<std::shared_ptr<RawTile>> readyResults;
while (_concurrentJobManager.numFinishedJobs() > 0) {
readyResults.push_back(_concurrentJobManager.popFinishedJob()->product());
}
return readyResults;
}
bool AsyncTileDataProvider::satisfiesEnqueueCriteria(const TileIndex& tileIndex) const {
// only allow tile to be enqueued if it's not already enqueued
//return _futureTileIOResults.find(tileIndex.hashKey()) == _futureTileIOResults.end();
return _enqueuedTileRequests.find(tileIndex.hashKey()) == _enqueuedTileRequests.end();
bool AsyncTileDataProvider::satisfiesEnqueueCriteria(const TileIndex& tileIndex) const {
// only allow tile to be enqueued if it's not already enqueued
//return _futureTileIOResults.find(tileIndex.hashKey()) == _futureTileIOResults.end();
return _enqueuedTileRequests.find(tileIndex.hashKey()) == _enqueuedTileRequests.end();
}
void AsyncTileDataProvider::reset() {
//_futureTileIOResults.clear();
//_threadPool->stop(ghoul::ThreadPool::RunRemainingTasks::No);
//_threadPool->start();
_enqueuedTileRequests.clear();
_concurrentJobManager.reset();
while (_concurrentJobManager.numFinishedJobs() > 0) {
_concurrentJobManager.popFinishedJob();
}
getTextureDataProvider()->reset();
}
void AsyncTileDataProvider::reset() {
//_futureTileIOResults.clear();
//_threadPool->stop(ghoul::ThreadPool::RunRemainingTasks::No);
//_threadPool->start();
_enqueuedTileRequests.clear();
_concurrentJobManager.reset();
while (_concurrentJobManager.numFinishedJobs() > 0) {
_concurrentJobManager.popFinishedJob();
}
getTextureDataProvider()->reset();
}
void AsyncTileDataProvider::clearRequestQueue() {
//_threadPool->clearRemainingTasks();
//_futureTileIOResults.clear();
_concurrentJobManager.clearEnqueuedJobs();
_enqueuedTileRequests.clear();
}
void AsyncTileDataProvider::clearRequestQueue() {
//_threadPool->clearRemainingTasks();
//_futureTileIOResults.clear();
_concurrentJobManager.clearEnqueuedJobs();
_enqueuedTileRequests.clear();
}
float AsyncTileDataProvider::noDataValueAsFloat() {
return _tileDataset->noDataValueAsFloat();
}
float AsyncTileDataProvider::noDataValueAsFloat() {
return _tileDataset->noDataValueAsFloat();
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,134 +1,110 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_ASYNC_TILE_DATA_PROVIDER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_ASYNC_TILE_DATA_PROVIDER_H__
#ifndef __ASYNC_TILE_DATA_PROVIDER_H__
#define __ASYNC_TILE_DATA_PROVIDER_H__
//#include <modules/globebrowsing/other/tileprovider.h>
#include <ghoul/opengl/texture.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/other/concurrentjobmanager.h>
#include <modules/globebrowsing/other/threadpool.h>
//#include <ghoul/misc/threadpool.h>
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/tile/tiledataset.h>
#include <memory>
#include <queue>
#include <unordered_map>
#include <sstream>
namespace openspace {
namespace globebrowsing {
struct LoadJob : public Job<RawTile> {
virtual void execute() = 0;
virtual std::shared_ptr<RawTile> product() = 0;
class TileDataset;
struct LoadJob : public Job<RawTile> {
virtual void execute() = 0;
virtual std::shared_ptr<RawTile> product() const = 0;
};
struct TileLoadJob : LoadJob {
TileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex)
: _tileDataset(textureDataProvider)
, _chunkIndex(tileIndex)
{}
virtual ~TileLoadJob() = default;
virtual void execute() override;
virtual std::shared_ptr<RawTile> product() const override;
protected:
TileIndex _chunkIndex;
std::shared_ptr<TileDataset> _tileDataset;
std::shared_ptr<RawTile> _rawTile;
};
class TileDiskCache;
struct DiskCachedTileLoadJob : public TileLoadJob {
enum CacheMode {
Disabled,
ReadOnly,
ReadAndWrite,
WriteOnly,
CacheHitsOnly,
};
struct TileLoadJob : LoadJob {
TileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex)
: _tileDataset(textureDataProvider)
, _chunkIndex(tileIndex)
{}
virtual ~TileLoadJob() { }
virtual void execute();
virtual std::shared_ptr<RawTile> product() {
return _rawTile;
}
protected:
TileIndex _chunkIndex;
std::shared_ptr<TileDataset> _tileDataset;
std::shared_ptr<RawTile> _rawTile;
};
class TileDiskCache;
struct DiskCachedTileLoadJob : public TileLoadJob {
enum CacheMode {
Disabled,
ReadOnly,
ReadAndWrite,
WriteOnly,
CacheHitsOnly,
};
DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc,
const std::string cacheMode);
DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc,
CacheMode cacheMode = CacheMode::ReadOnly);
DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc,
CacheMode cacheMode = CacheMode::ReadOnly);
void execute() override;
virtual void execute();
protected:
std::shared_ptr<TileDiskCache> _tileDiskCache;
CacheMode _mode;
};
protected:
std::shared_ptr<TileDiskCache> _tileDiskCache;
CacheMode _mode;
class AsyncTileDataProvider {
public:
AsyncTileDataProvider(std::shared_ptr<TileDataset> textureDataProvider,
std::shared_ptr<ThreadPool> pool);
};
class AsyncTileDataProvider {
public:
AsyncTileDataProvider(std::shared_ptr<TileDataset> textureDataProvider,
std::shared_ptr<ThreadPool> pool);
~AsyncTileDataProvider();
bool enqueueTileIO(const TileIndex& tileIndex);
std::vector<std::shared_ptr<RawTile>> getRawTiles();
bool enqueueTileIO(const TileIndex& tileIndex);
std::vector<std::shared_ptr<RawTile>> getRawTiles();
void reset();
void clearRequestQueue();
void reset();
void clearRequestQueue();
std::shared_ptr<TileDataset> getTextureDataProvider() const;
float noDataValueAsFloat();
std::shared_ptr<TileDataset> getTextureDataProvider() const;
float noDataValueAsFloat();
protected:
virtual bool satisfiesEnqueueCriteria(const TileIndex&) const;
protected:
virtual bool satisfiesEnqueueCriteria(const TileIndex&) const;
private:
std::shared_ptr<TileDataset> _tileDataset;
ConcurrentJobManager<RawTile> _concurrentJobManager;
std::unordered_map<TileHashKey, TileIndex> _enqueuedTileRequests;
};
private:
std::shared_ptr<TileDataset> _tileDataset;
ConcurrentJobManager<RawTile> _concurrentJobManager;
std::unordered_map<TileHashKey, TileIndex> _enqueuedTileRequests;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __ASYNC_TILE_DATA_PROVIDER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_ASYNC_TILE_DATA_PROVIDER_H__

View File

@@ -1,37 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/chunktile.h>
#include <ghoul/logging/logmanager.h>
namespace {
const std::string _loggerCat = "ChunkTile";
}
namespace openspace {
namespace globebrowsing {
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,52 +1,49 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILEANDTRANSFORM_H__
#define __TILEANDTRANSFORM_H__
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKTILE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKTILE_H__
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/tile/tiledepthtransform.h>
#include <vector>
namespace openspace {
namespace globebrowsing {
using namespace ghoul::opengl;
struct ChunkTile {
Tile tile;
TileUvTransform uvTransform;
TileDepthTransform depthTransform;
};
struct ChunkTile {
Tile tile;
TileUvTransform uvTransform;
TileDepthTransform depthTransform;
};
struct ChunkTilePile {
std::vector<ChunkTile> chunkTiles;
};
struct ChunkTilePile {
std::vector<ChunkTile> chunkTiles;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILEANDTRANSFORM_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKTILE_H__

View File

@@ -1,252 +1,255 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/pixelregion.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <iostream>
namespace {
const std::string _loggerCat = "PixelRegion";
}
namespace openspace {
namespace globebrowsing {
PixelRegion::PixelRegion()
: start(0)
, numPixels(0)
{}
PixelRegion::PixelRegion(const PixelCoordinate& pixelStart,
const PixelRange& numberOfPixels)
: start(pixelStart)
, numPixels(numberOfPixels)
{}
PixelRegion::PixelRegion(const PixelRegion& o)
: start(o.start)
, numPixels(o.numPixels)
{}
PixelRegion::PixelRegion(const PixelRegion& o)
: start(o.start)
, numPixels(o.numPixels)
{}
PixelRegion::PixelRegion(const PixelCoordinate& pixelStart, const PixelRange& numberOfPixels)
: start(pixelStart)
, numPixels(numberOfPixels)
{}
//////////////////////////////////////////////////////////////////////////////////
// Mutators //
//////////////////////////////////////////////////////////////////////////////////
void PixelRegion::setSide(Side side, int pos) {
switch (side) {
case LEFT: setLeft(pos); break;
case TOP: setTop(pos); break;
case RIGHT: setRight(pos); break;
case BOTTOM: setBottom(pos); break;
}
}
void PixelRegion::setLeft(int x) {
numPixels.x += (start.x - x);
start.x = x;
}
void PixelRegion::setTop(int p) {
numPixels.y += (start.y - p);
start.y = p;
}
void PixelRegion::setRight(int x) {
numPixels.x = x - start.x;
}
void PixelRegion::setBottom(int y) {
numPixels.y = y - start.y;
}
void PixelRegion::align(Side side, int pos) {
switch (side) {
case LEFT: alignLeft(pos); break;
case TOP: alignTop(pos); break;
case RIGHT: alignRight(pos); break;
case BOTTOM: alignBottom(pos); break;
}
}
void PixelRegion::alignLeft(int x) {
start.x = x;
}
void PixelRegion::alignTop(int y) {
start.y = y;
}
void PixelRegion::alignRight(int x) {
start.x = x - numPixels.x;
}
void PixelRegion::alignBottom(int y) {
start.y = y - numPixels.y;
}
void PixelRegion::scale(const glm::dvec2& s) {
start = PixelCoordinate(glm::round(s * glm::dvec2(start)));
numPixels = PixelCoordinate(glm::round(s * glm::dvec2(numPixels)));
}
void PixelRegion::scale(double s) {
scale(glm::dvec2(s));
}
void PixelRegion::downscalePow2(int exponent, PixelCoordinate wrt) {
start += wrt;
start.x >>= exponent;
start.y >>= exponent;
numPixels.x >>= exponent;
numPixels.y >>= exponent;
start -= wrt;
}
void PixelRegion::upscalePow2(int exponent, PixelCoordinate wrt) {
start += wrt;
start.x <<= exponent;
start.y <<= exponent;
numPixels.x <<= exponent;
numPixels.y <<= exponent;
start -= wrt;
}
void PixelRegion::move(Side side, int amount) {
switch (side) {
case LEFT: start.x -= amount; break;
case TOP: start.y -= amount; break;
case RIGHT: start.x += amount; break;
case BOTTOM: start.y += amount; break;
}
}
void PixelRegion::pad(const PixelRegion& padding) {
start += padding.start;
numPixels += padding.numPixels;
}
void PixelRegion::clampTo(const PixelRegion& boundingRegion) {
start = glm::max(start, boundingRegion.start);
numPixels = glm::min(end(), boundingRegion.end()) - start;
}
void PixelRegion::forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple) {
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
int sizeDiff = numPixels.x - numPixels.y;
if (std::abs(sizeDiff) > 0) {
if (sizeDiff > 0) {
numPixels.y += sizeDiff % multiple;
}
else {
numPixels.x += std::abs(sizeDiff) % multiple;
}
}
}
void PixelRegion::roundUpNumPixelToNearestMultipleOf(unsigned int multiple) {
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
numPixels.x += numPixels.x % multiple;
numPixels.y += numPixels.y % multiple;
}
void PixelRegion::roundDownToQuadratic() {
if (numPixels.x < numPixels.y) {
numPixels.y = numPixels.x;
}
else if (numPixels.x > numPixels.y) {
numPixels.x = numPixels.y;
}
}
PixelRegion PixelRegion::globalCut(Side side, int p) {
if (!lineIntersect(side, p)) {
return PixelRegion({ 0, 0 }, { 0, 0 });
}
PixelRegion cutOff(*this);
int cutSize = 0;
switch (side) {
void PixelRegion::setSide(Side side, int pos) {
switch (side) {
case LEFT:
setLeft(p);
cutOff.setRight(p - cutSize);
setLeft(pos);
break;
case TOP:
setTop(p);
cutOff.setBottom(p - cutSize);
setTop(pos);
break;
case RIGHT:
setRight(p);
cutOff.setLeft(p + cutSize);
setRight(pos);
break;
case BOTTOM:
setBottom(p);
cutOff.setTop(p + cutSize);
setBottom(pos);
break;
}
}
void PixelRegion::setLeft(int x) {
numPixels.x += (start.x - x);
start.x = x;
}
void PixelRegion::setTop(int p) {
numPixels.y += (start.y - p);
start.y = p;
}
void PixelRegion::setRight(int x) {
numPixels.x = x - start.x;
}
void PixelRegion::setBottom(int y) {
numPixels.y = y - start.y;
}
void PixelRegion::align(Side side, int pos) {
switch (side) {
case LEFT:
alignLeft(pos);
break;
case TOP:
alignTop(pos);
break;
case RIGHT:
alignRight(pos);
break;
case BOTTOM:
alignBottom(pos);
break;
}
}
void PixelRegion::alignLeft(int x) {
start.x = x;
}
void PixelRegion::alignTop(int y) {
start.y = y;
}
void PixelRegion::alignRight(int x) {
start.x = x - numPixels.x;
}
void PixelRegion::alignBottom(int y) {
start.y = y - numPixels.y;
}
void PixelRegion::scale(const glm::dvec2& s) {
start = PixelCoordinate(glm::round(s * glm::dvec2(start)));
numPixels = PixelCoordinate(glm::round(s * glm::dvec2(numPixels)));
}
void PixelRegion::scale(double s) {
scale(glm::dvec2(s));
}
void PixelRegion::downscalePow2(int exponent, PixelCoordinate wrt) {
start += wrt;
start.x >>= exponent;
start.y >>= exponent;
numPixels.x >>= exponent;
numPixels.y >>= exponent;
start -= wrt;
}
void PixelRegion::upscalePow2(int exponent, PixelCoordinate wrt) {
start += wrt;
start.x <<= exponent;
start.y <<= exponent;
numPixels.x <<= exponent;
numPixels.y <<= exponent;
start -= wrt;
}
void PixelRegion::move(Side side, int amount) {
switch (side) {
case LEFT:
start.x -= amount;
break;
case TOP:
start.y -= amount;
break;
case RIGHT:
start.x += amount;
break;
case BOTTOM:
start.y += amount;
break;
}
}
void PixelRegion::pad(const PixelRegion& padding) {
start += padding.start;
numPixels += padding.numPixels;
}
void PixelRegion::clampTo(const PixelRegion& boundingRegion) {
start = glm::max(start, boundingRegion.start);
numPixels = glm::min(end(), boundingRegion.end()) - start;
}
void PixelRegion::forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple) {
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
int sizeDiff = numPixels.x - numPixels.y;
if (std::abs(sizeDiff) > 0) {
if (sizeDiff > 0) {
numPixels.y += sizeDiff % multiple;
}
return cutOff;
}
PixelRegion PixelRegion::localCut(Side side, int p) {
if (p < 1) {
return PixelRegion({ 0, 0 }, { 0, 0 });
}
else return globalCut(side, edge(side) - edgeDirectionSign(side) * p);
}
//////////////////////////////////////////////////////////////////////////////////
// Accessors //
//////////////////////////////////////////////////////////////////////////////////
int PixelRegion::area() const {
return numPixels.x * numPixels.y;
}
int PixelRegion::edge(Side side) const {
switch (side) {
case LEFT: return start.x;
case TOP: return start.y;
case RIGHT: return start.x + numPixels.x;
case BOTTOM: return start.y + numPixels.y;
else {
numPixels.x += std::abs(sizeDiff) % multiple;
}
}
}
int PixelRegion::edgeDirectionSign(Side side) const {
return side < RIGHT ? -1 : 1;
void PixelRegion::roundUpNumPixelToNearestMultipleOf(unsigned int multiple) {
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
numPixels.x += numPixels.x % multiple;
numPixels.y += numPixels.y % multiple;
}
void PixelRegion::roundDownToQuadratic() {
if (numPixels.x < numPixels.y) {
numPixels.y = numPixels.x;
}
else if (numPixels.x > numPixels.y) {
numPixels.x = numPixels.y;
}
}
PixelRegion PixelRegion::globalCut(Side side, int p) {
if (!lineIntersect(side, p)) {
return PixelRegion({ 0, 0 }, { 0, 0 });
}
PixelCoordinate PixelRegion::end() const {
return start + numPixels;
PixelRegion cutOff(*this);
int cutSize = 0;
switch (side) {
case LEFT:
setLeft(p);
cutOff.setRight(p - cutSize);
break;
case TOP:
setTop(p);
cutOff.setBottom(p - cutSize);
break;
case RIGHT:
setRight(p);
cutOff.setLeft(p + cutSize);
break;
case BOTTOM:
setBottom(p);
cutOff.setTop(p + cutSize);
break;
}
return cutOff;
}
//////////////////////////////////////////////////////////////////////////////////
// Comparators //
//////////////////////////////////////////////////////////////////////////////////
PixelRegion PixelRegion::localCut(Side side, int p) {
if (p < 1) {
return PixelRegion({ 0, 0 }, { 0, 0 });
}
else {
return globalCut(side, edge(side) - edgeDirectionSign(side) * p);
}
}
bool PixelRegion::lineIntersect(Side side, int p) {
switch (side)
{
int PixelRegion::area() const {
return numPixels.x * numPixels.y;
}
int PixelRegion::edge(Side side) const {
switch (side) {
case LEFT: return start.x;
case TOP: return start.y;
case RIGHT: return start.x + numPixels.x;
case BOTTOM: return start.y + numPixels.y;
}
}
int PixelRegion::edgeDirectionSign(Side side) const {
return side < RIGHT ? -1 : 1;
}
PixelCoordinate PixelRegion::end() const {
return start + numPixels;
}
bool PixelRegion::lineIntersect(Side side, int p) {
switch (side) {
case PixelRegion::LEFT:
case PixelRegion::RIGHT:
return start.x <= p && p <= (start.x + numPixels.x);
@@ -254,19 +257,18 @@ namespace globebrowsing {
case PixelRegion::TOP:
case PixelRegion::BOTTOM:
return start.y <= p && p <= (start.y + numPixels.y);
}
}
}
bool PixelRegion::isInside(const PixelRegion& r) const {
PixelCoordinate e = end();
PixelCoordinate re = r.end();
return r.start.x <= start.x && e.x <= re.x
&& r.start.y <= start.y && e.y <= re.y;
}
bool PixelRegion::isInside(const PixelRegion& r) const {
PixelCoordinate e = end();
PixelCoordinate re = r.end();
return r.start.x <= start.x && e.x <= re.x && r.start.y <= start.y && e.y <= re.y;
}
bool PixelRegion::equals(const PixelRegion& r) const {
return start == r.start && numPixels == r.numPixels;
}
bool PixelRegion::equals(const PixelRegion& r) const {
return start == r.start && numPixels == r.numPixels;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,120 +1,106 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __PIXEL_REGION_H__
#define __PIXEL_REGION_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_PIXELREGION_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_PIXELREGION_H__
#include <glm/glm.hpp>
namespace openspace {
namespace globebrowsing {
typedef glm::ivec2 PixelCoordinate;
typedef glm::ivec2 PixelRange;
using PixelCoordinate = glm::ivec2;
using PixelRange= glm::ivec2;
struct PixelRegion {
enum Side {
LEFT = 0, TOP, RIGHT, BOTTOM,
};
PixelRegion();
PixelRegion(const PixelRegion& o);
PixelRegion(const PixelCoordinate& pixelStart, const PixelRange& numberOfPixels);
//////////////////////////////////////////////////////////////////////////////////
// Mutators //
//////////////////////////////////////////////////////////////////////////////////
/**
* Sets one of the sides of the pixel region the specified position. This changes
* the number of pixels in the region.
*
* Example: side = LEFT and pos 16:
* set start.x = 16 and keep the end position the same.
*/
void setSide(Side side, int pos);
void setLeft(int x);
void setTop(int p);
void setRight(int x);
void setBottom(int y);
/**
* Aligns one the sides of the pixel regino to the specified position. This does
* not change the number of pixels within the region.
*
* Example: Side = left and pos = 16:
* start.x = 16 and keep the size the same
*/
void align(Side side, int pos);
void alignLeft(int x);
void alignTop(int y);
void alignRight(int x);
void alignBottom(int y);
void scale(const glm::dvec2& s);
void scale(double s);
void downscalePow2(int exponent, PixelCoordinate wrt = {0,0});
void upscalePow2(int exponent, PixelCoordinate wrt = { 0,0 });
void move(Side side, int amount);
void pad(const PixelRegion& padding);
void clampTo(const PixelRegion& boundingRegion);
void forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple);
void roundUpNumPixelToNearestMultipleOf(unsigned int multiple);
void roundDownToQuadratic();
PixelRegion globalCut(Side side, int globalPos);
PixelRegion localCut(Side side, int localPos);
//////////////////////////////////////////////////////////////////////////////////
// Accessors //
//////////////////////////////////////////////////////////////////////////////////
int area() const;
int edge(Side side) const;
int edgeDirectionSign(Side side) const;
PixelCoordinate end() const;
//////////////////////////////////////////////////////////////////////////////////
// Comparators //
//////////////////////////////////////////////////////////////////////////////////
bool lineIntersect(Side side, int p);
bool isInside(const PixelRegion& r) const;
bool equals(const PixelRegion& r) const;
//////////////////////////////////////////////////////////////////////////////////
// Members //
//////////////////////////////////////////////////////////////////////////////////
PixelCoordinate start;
PixelRange numPixels;
struct PixelRegion {
enum Side {
LEFT = 0,
TOP,
RIGHT,
BOTTOM
};
PixelRegion(const PixelRegion& o);
PixelRegion(const PixelCoordinate& pixelStart = PixelCoordinate(0, 0),
const PixelRange& numberOfPixels = PixelRange(0, 0));
/**
* Sets one of the sides of the pixel region the specified position. This changes
* the number of pixels in the region.
*
* Example: side = LEFT and pos 16:
* set start.x = 16 and keep the end position the same.
*/
void setSide(Side side, int pos);
void setLeft(int x);
void setTop(int p);
void setRight(int x);
void setBottom(int y);
/**
* Aligns one the sides of the pixel regino to the specified position. This does
* not change the number of pixels within the region.
*
* Example: Side = left and pos = 16:
* start.x = 16 and keep the size the same
*/
void align(Side side, int pos);
void alignLeft(int x);
void alignTop(int y);
void alignRight(int x);
void alignBottom(int y);
void scale(const glm::dvec2& s);
void scale(double s);
void downscalePow2(int exponent, PixelCoordinate wrt = {0,0});
void upscalePow2(int exponent, PixelCoordinate wrt = { 0,0 });
void move(Side side, int amount);
void pad(const PixelRegion& padding);
void clampTo(const PixelRegion& boundingRegion);
void forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple);
void roundUpNumPixelToNearestMultipleOf(unsigned int multiple);
void roundDownToQuadratic();
PixelRegion globalCut(Side side, int globalPos);
PixelRegion localCut(Side side, int localPos);
int area() const;
int edge(Side side) const;
int edgeDirectionSign(Side side) const;
PixelCoordinate end() const;
bool lineIntersect(Side side, int p);
bool isInside(const PixelRegion& r) const;
bool equals(const PixelRegion& r) const;
PixelCoordinate start;
PixelRange numPixels;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __PIXEL_REGION_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_PIXELREGION_H__

View File

@@ -1,30 +1,30 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tiledataset.h>
#include <ghoul/logging/logmanager.h>
#include <gdal_priv.h>
namespace {
const std::string _loggerCat = "Tile";
@@ -33,150 +33,144 @@ namespace {
namespace openspace {
namespace globebrowsing {
void TileMetaData::serialize(std::ostream& os) {
os << maxValues.size() << std::endl;
for (float f : maxValues) {
os << f << " ";
}
os << std::endl;
for (float f : minValues) {
os << f << " ";
}
os << std::endl;
}
void TileMetaData::serialize(std::ostream& os) {
os << maxValues.size() << std::endl;
for (float f : maxValues) {
os << f << " ";
}
os << std::endl;
for (float f : minValues) {
os << f << " ";
}
os << std::endl;
TileMetaData TileMetaData::deserialize(std::istream& is) {
TileMetaData res;
int n; is >> n;
res.maxValues.resize(n);
for (int i = 0; i < n; i++) {
is >> res.maxValues[i];
}
res.minValues.resize(n);
for (int i = 0; i < n; i++) {
is >> res.minValues[i];
}
TileMetaData TileMetaData::deserialize(std::istream& is) {
TileMetaData res;
int n; is >> n;
res.maxValues.resize(n);
for (int i = 0; i < n; i++) {
is >> res.maxValues[i];
}
res.minValues.resize(n);
for (int i = 0; i < n; i++) {
is >> res.minValues[i];
}
return std::move(res);
}
return std::move(res);
RawTile::RawTile()
: imageData(nullptr)
, dimensions(0, 0, 0)
, tileMetaData(nullptr)
, tileIndex(0, 0, 0)
, error(CE_None)
, nBytesImageData(0)
{}
RawTile RawTile::createDefaultRes() {
RawTile defaultRes;
int w = 8;
int h = 8;
defaultRes.dimensions = glm::uvec3(w, h, 1);
defaultRes.nBytesImageData = w * h * 1 * 3 * 4; // assume max 3 channels, max 4 bytes per pixel
defaultRes.imageData = new char[defaultRes.nBytesImageData];
std::fill_n((char*)defaultRes.imageData, defaultRes.nBytesImageData, 0);
return std::move(defaultRes);
}
void RawTile::serializeMetaData(std::ostream& os) {
os << dimensions.x << " " << dimensions.y << " " << dimensions.z << std::endl;
os << tileIndex.x << " " << tileIndex.y << " " << tileIndex.level << std::endl;
os << error << std::endl;
// preprocess data
os << (tileMetaData != nullptr) << std::endl;
if (tileMetaData != nullptr) {
tileMetaData->serialize(os);
}
RawTile::RawTile()
: imageData(nullptr)
, dimensions(0, 0, 0)
, tileMetaData(nullptr)
, tileIndex(0, 0, 0)
, error(CE_None)
, nBytesImageData(0)
{}
RawTile RawTile::createDefaultRes() {
RawTile defaultRes;
int w = 8;
int h = 8;
defaultRes.dimensions = glm::uvec3(w, h, 1);
defaultRes.nBytesImageData = w * h * 1 * 3 * 4; // assume max 3 channels, max 4 bytes per pixel
defaultRes.imageData = new char[defaultRes.nBytesImageData];
std::fill_n((char*)defaultRes.imageData, defaultRes.nBytesImageData, 0);
return std::move(defaultRes);
os << nBytesImageData << std::endl;
}
RawTile RawTile::deserializeMetaData(std::istream& is) {
RawTile res;
is >> res.dimensions.x >> res.dimensions.y >> res.dimensions.z;
is >> res.tileIndex.x >> res.tileIndex.y >> res.tileIndex.level;
int err; is >> err; res.error = (CPLErr) err;
res.tileMetaData = nullptr;
bool hastileMetaData;
is >> hastileMetaData;
if (hastileMetaData) {
TileMetaData tileMetaData = TileMetaData::deserialize(is);
res.tileMetaData = std::make_shared<TileMetaData>(tileMetaData);
}
void RawTile::serializeMetaData(std::ostream& os) {
os << dimensions.x << " " << dimensions.y << " " << dimensions.z << std::endl;
os << tileIndex.x << " " << tileIndex.y << " " << tileIndex.level << std::endl;
os << error << std::endl;
// preprocess data
os << (tileMetaData != nullptr) << std::endl;
if (tileMetaData != nullptr) {
tileMetaData->serialize(os);
}
os << nBytesImageData << std::endl;
}
is >> res.nBytesImageData;
RawTile RawTile::deserializeMetaData(std::istream& is) {
RawTile res;
is >> res.dimensions.x >> res.dimensions.y >> res.dimensions.z;
is >> res.tileIndex.x >> res.tileIndex.y >> res.tileIndex.level;
int err; is >> err; res.error = (CPLErr) err;
char binaryDataSeparator;
is >> binaryDataSeparator; // not used
res.tileMetaData = nullptr;
bool hastileMetaData;
is >> hastileMetaData;
if (hastileMetaData) {
TileMetaData tileMetaData = TileMetaData::deserialize(is);
res.tileMetaData = std::make_shared<TileMetaData>(tileMetaData);
}
is >> res.nBytesImageData;
char* buffer = new char[res.nBytesImageData]();
return std::move(res);
}
char binaryDataSeparator;
is >> binaryDataSeparator; // not used
char* buffer = new char[res.nBytesImageData]();
return std::move(res);
}
const Tile Tile::TileUnavailable = {nullptr, nullptr, Tile::Status::Unavailable };
const Tile Tile::TileUnavailable = {nullptr, nullptr, Tile::Status::Unavailable };
Tile Tile::createPlainTile(const glm::uvec2& size, const glm::uvec4& color) {
using namespace ghoul::opengl;
Tile Tile::createPlainTile(const glm::uvec2& size, const glm::uvec4& color) {
using namespace ghoul::opengl;
// Create pixel data
int numBytes = size.x * size.y * 4 * 1;
char* pixels = new char[numBytes];
size_t numPixels = size.x * size.y;
size_t i = 0;
for (size_t p = 0; p < numPixels; p++){
pixels[i++] = color.r;
pixels[i++] = color.g;
pixels[i++] = color.b;
pixels[i++] = color.a;
}
// Create ghoul texture
auto texture = std::make_shared<Texture>(glm::uvec3(size, 1));
texture->setDataOwnership(Texture::TakeOwnership::Yes);
texture->setPixelData(pixels);
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
// Create tile
Tile tile;
tile.status = Tile::Status::OK;
tile.metaData = nullptr;
tile.texture = texture;
return tile;
// Create pixel data
int numBytes = size.x * size.y * 4 * 1;
char* pixels = new char[numBytes];
size_t numPixels = size.x * size.y;
size_t i = 0;
for (size_t p = 0; p < numPixels; p++){
pixels[i++] = color.r;
pixels[i++] = color.g;
pixels[i++] = color.b;
pixels[i++] = color.a;
}
glm::vec2 Tile::compensateSourceTextureSampling(
glm::vec2 startOffset,
glm::vec2 sizeDiff,
glm::uvec2 resolution,
glm::vec2 tileUV) {
glm::vec2 sourceSize = glm::vec2(resolution) + sizeDiff;
glm::vec2 currentSize = glm::vec2(resolution);
glm::vec2 sourceToCurrentSize = currentSize / sourceSize;
tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize);
return tileUV;
}
// Create ghoul texture
auto texture = std::make_shared<Texture>(glm::uvec3(size, 1));
texture->setDataOwnership(Texture::TakeOwnership::Yes);
texture->setPixelData(pixels);
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
glm::vec2 Tile::TileUvToTextureSamplePosition(
const TileUvTransform uvTransform,
glm::vec2 tileUV,
glm::uvec2 resolution) {
glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV;
uv = compensateSourceTextureSampling(
TileDataset::tilePixelStartOffset,
TileDataset::tilePixelSizeDifference,
resolution,
uv);
return uv;
}
// Create tile
Tile tile;
tile.status = Tile::Status::OK;
tile.metaData = nullptr;
tile.texture = texture;
return tile;
}
glm::vec2 Tile::compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff,
glm::uvec2 resolution, glm::vec2 tileUV)
{
glm::vec2 sourceSize = glm::vec2(resolution) + sizeDiff;
glm::vec2 currentSize = glm::vec2(resolution);
glm::vec2 sourceToCurrentSize = currentSize / sourceSize;
tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize);
return tileUV;
}
glm::vec2 Tile::TileUvToTextureSamplePosition(const TileUvTransform uvTransform,
glm::vec2 tileUV, glm::uvec2 resolution)
{
glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV;
uv = compensateSourceTextureSampling(
TileDataset::tilePixelStartOffset,
TileDataset::tilePixelSizeDifference,
resolution,
uv);
return uv;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,41 +1,40 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_H__
#define __TILE_H__
#include <ghoul/opengl/texture.h> // Texture
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_H__
#include <modules/globebrowsing/tile/tileindex.h>
#include <memory>
#include <ghoul/opengl/texture.h>
#include <gdal_priv.h>
#include <cpl_error.h>
#include <memory>
#include <vector>
namespace openspace {
namespace globebrowsing {
struct TileMetaData {
std::vector<float> maxValues;
@@ -67,88 +66,78 @@ struct RawTile {
static RawTile deserializeMetaData(std::istream& s);
static RawTile createDefaultRes();
};
struct TileUvTransform {
glm::vec2 uvOffset;
glm::vec2 uvScale;
};
/**
* Defines a status and may have a Texture and TileMetaData
*/
* Defines a status and may have a Texture and TileMetaData
*/
struct Tile {
std::shared_ptr<Texture> texture;
std::shared_ptr<TileMetaData> metaData;
/**
* Describe if this Tile is good for usage (OK) or otherwise
* the reason why it is not.
*/
* Describe if this Tile is good for usage (OK) or otherwise
* the reason why it is not.
*/
enum class Status {
/**
* E.g when texture data is not currently in memory.
* texture and tileMetaData are both null
*/
* E.g when texture data is not currently in memory.
* texture and tileMetaData are both null
*/
Unavailable,
/**
* Can be set by <code>TileProvider</code>s if the requested
* <code>TileIndex</code> is undefined for that particular
* provider.
* texture and metaData are both null
*/
* Can be set by <code>TileProvider</code>s if the requested
* <code>TileIndex</code> is undefined for that particular
* provider.
* texture and metaData are both null
*/
OutOfRange,
/**
* An IO Error happend
* texture and metaData are both null
*/
* An IO Error happend
* texture and metaData are both null
*/
IOError,
/**
* The Texture is uploaded to the GPU and good for usage.
* texture is defined. metaData may be defined.
*/
* The Texture is uploaded to the GPU and good for usage.
* texture is defined. metaData may be defined.
*/
OK
} status;
/**
* Instantiates a new tile with a single color.
*
* \param size The size of texture to be created
* \param color defined RGBA values in range 0-255.
*
* \returns a Tile with status OK and the a texture
* with the requested size and color
*/
* Instantiates a new tile with a single color.
*
* \param size The size of texture to be created
* \param color defined RGBA values in range 0-255.
*
* \returns a Tile with status OK and the a texture
* with the requested size and color
*/
static Tile createPlainTile(const glm::uvec2& size, const glm::uvec4& color);
static glm::vec2 compensateSourceTextureSampling(
glm::vec2 startOffset,
glm::vec2 sizeDiff,
glm::uvec2 resolution,
glm::vec2 tileUV);
static glm::vec2 compensateSourceTextureSampling(glm::vec2 startOffset,
glm::vec2 sizeDiff, glm::uvec2 resolution, glm::vec2 tileUV);
static glm::vec2 TileUvToTextureSamplePosition(
const TileUvTransform uvTransform,
glm::vec2 tileUV,
glm::uvec2 resolution);
static glm::vec2 TileUvToTextureSamplePosition(const TileUvTransform uvTransform,
glm::vec2 tileUV, glm::uvec2 resolution);
/**
* A tile with status unavailable that any user can return to
* indicate that a tile was unavailable.
*/
* A tile with status unavailable that any user can return to
* indicate that a tile was unavailable.
*/
static const Tile TileUnavailable;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,203 +1,198 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_DATASET_H__
#define __TILE_DATASET_H__
#include <memory>
#include <set>
#include <queue>
#include <iostream>
#include <unordered_map>
#include <ghoul/filesystem/file.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/misc/threadpool.h>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATASET_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATASET_H__
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/tile/tiledatatype.h>
#include <modules/globebrowsing/tile/tiledepthtransform.h>
#include <modules/globebrowsing/tile/tiledataset.h>
#include <modules/globebrowsing/tile/pixelregion.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <ghoul/glm.h>
#include <ghoul/opengl/ghoul_gl.h>
#include <gdal.h>
#include <string>
class GDALDataset;
class GDALRasterBand;
namespace openspace {
namespace globebrowsing {
struct TileDataLayout {
TileDataLayout();
TileDataLayout(GDALDataset* dataSet, GLuint preferredGlType);
class GeodeticPatch;
GDALDataType gdalType;
GLuint glType;
struct TileDataLayout {
TileDataLayout();
TileDataLayout(GDALDataset* dataSet, GLuint preferredGlType);
size_t bytesPerDatum;
size_t numRasters;
size_t bytesPerPixel;
GDALDataType gdalType;
GLuint glType;
TextureFormat textureFormat;
size_t bytesPerDatum;
size_t numRasters;
size_t bytesPerPixel;
TextureFormat textureFormat;
};
struct IODescription {
struct ReadData {
int overview;
PixelRegion region;
} read;
struct WriteData {
PixelRegion region;
size_t bytesPerLine;
size_t totalNumBytes;
} write;
IODescription cut(PixelRegion::Side side, int pos);
};
class TileDataset {
public:
struct Configuration {
bool doPreProcessing;
int minimumTilePixelSize;
GLuint dataType = 0; // default = no datatype reinterpretation
};
struct IODescription {
struct ReadData {
int overview;
PixelRegion region;
} read;
/**
* Opens a GDALDataset in readonly mode and calculates meta data required for
* reading tile using a TileIndex.
*
* \param gdalDatasetDesc - A path to a specific file or raw XML describing the dataset
* \param minimumPixelSize - minimum number of pixels per side per tile requested
* \param datatype - datatype for storing pixel data in requested tile
*/
TileDataset(const std::string& gdalDatasetDesc, const Configuration& config);
struct WriteData {
PixelRegion region;
size_t bytesPerLine;
size_t totalNumBytes;
} write;
~TileDataset();
IODescription cut(PixelRegion::Side side, int pos);
};
using namespace ghoul::opengl;
using namespace ghoul::filesystem;
//////////////////////////////////////////////////////////////////////////////////
// Public interface //
//////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<RawTile> readTileData(TileIndex tileIndex);
std::shared_ptr<RawTile> defaultTileData();
int maxChunkLevel();
TileDepthTransform getDepthTransform();
const TileDataLayout& getDataLayout();
void reset();
float noDataValueAsFloat();
class TileDataset {
public:
struct Configuration {
bool doPreProcessing;
int minimumTilePixelSize;
GLuint dataType = 0; // default = no datatype reinterpretation
};
const static glm::ivec2 tilePixelStartOffset;
const static glm::ivec2 tilePixelSizeDifference;
const static PixelRegion padding; // same as the two above
private:
//////////////////////////////////////////////////////////////////////////////////
// Initialization //
//////////////////////////////////////////////////////////////////////////////////
void initialize();
void ensureInitialized();
TileDepthTransform calculateTileDepthTransform();
int calculateTileLevelDifference(int minimumPixelSize);
//////////////////////////////////////////////////////////////////////////////////
// GDAL helper methods //
//////////////////////////////////////////////////////////////////////////////////
void gdalEnsureInitialized();
void setGdalProxyConfiguration();
GDALDataset* gdalDataset(const std::string& gdalDatasetDesc);
bool gdalHasOverviews() const;
int gdalOverview(const PixelRange& baseRegionSize) const;
int gdalOverview(const TileIndex& tileIndex) const;
int gdalVirtualOverview(const TileIndex& tileIndex) const;
PixelRegion gdalPixelRegion(const GeodeticPatch& geodeticPatch) const;
PixelRegion gdalPixelRegion(GDALRasterBand* rasterBand) const;
GDALRasterBand* gdalRasterBand(int overview, int raster = 1) const;
//////////////////////////////////////////////////////////////////////////////////
// ReadTileData helper functions //
//////////////////////////////////////////////////////////////////////////////////
/**
Returns the geo transform from raster space to projection coordinates as defined
by GDAL.
If the transform is not available, the function returns a transform to map
the pixel coordinates to cover the whole geodetic lat long space.
*/
std::array<double, 6> getGeoTransform() const;
PixelCoordinate geodeticToPixel(const Geodetic2& geo) const;
Geodetic2 pixelToGeodetic(const PixelCoordinate& p) const;
IODescription getIODescription(const TileIndex& tileIndex) const;
char* readImageData(IODescription& io, CPLErr& worstError) const;
CPLErr rasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst) const;
CPLErr repeatedRasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst, int depth = 0) const;
std::shared_ptr<TileMetaData> getTileMetaData(std::shared_ptr<RawTile> result, const PixelRegion& region) const;
CPLErr postProcessErrorCheck(std::shared_ptr<const RawTile> ioResult, const IODescription& io) const;
//////////////////////////////////////////////////////////////////////////////////
// Member variables //
//////////////////////////////////////////////////////////////////////////////////
// init data
struct InitData {
std::string initDirectory;
std::string gdalDatasetDesc;
int minimumPixelSize;
GLuint dataType;
} _initData;
/**
* Opens a GDALDataset in readonly mode and calculates meta data required for
* reading tile using a TileIndex.
*
* \param gdalDatasetDesc - A path to a specific file or raw XML describing the dataset
* \param minimumPixelSize - minimum number of pixels per side per tile requested
* \param datatype - datatype for storing pixel data in requested tile
*/
TileDataset(const std::string& gdalDatasetDesc, const Configuration& config);
struct Cached {
int _maxLevel = -1;
double _tileLevelDifference;
} _cached;
~TileDataset();
const Configuration _config;
//////////////////////////////////////////////////////////////////////////////////
// Public interface //
//////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<RawTile> readTileData(TileIndex tileIndex);
std::shared_ptr<RawTile> defaultTileData();
int maxChunkLevel();
TileDepthTransform getDepthTransform();
const TileDataLayout& getDataLayout();
void reset();
float noDataValueAsFloat();
GDALDataset* _dataset;
TileDepthTransform _depthTransform;
TileDataLayout _dataLayout;
const static glm::ivec2 tilePixelStartOffset;
const static glm::ivec2 tilePixelSizeDifference;
const static PixelRegion padding; // same as the two above
private:
//////////////////////////////////////////////////////////////////////////////////
// Initialization //
//////////////////////////////////////////////////////////////////////////////////
void initialize();
void ensureInitialized();
TileDepthTransform calculateTileDepthTransform();
int calculateTileLevelDifference(int minimumPixelSize);
//////////////////////////////////////////////////////////////////////////////////
// GDAL helper methods //
//////////////////////////////////////////////////////////////////////////////////
void gdalEnsureInitialized();
void setGdalProxyConfiguration();
GDALDataset* gdalDataset(const std::string& gdalDatasetDesc);
bool gdalHasOverviews() const;
int gdalOverview(const PixelRange& baseRegionSize) const;
int gdalOverview(const TileIndex& tileIndex) const;
int gdalVirtualOverview(const TileIndex& tileIndex) const;
PixelRegion gdalPixelRegion(const GeodeticPatch& geodeticPatch) const;
PixelRegion gdalPixelRegion(GDALRasterBand* rasterBand) const;
GDALRasterBand* gdalRasterBand(int overview, int raster = 1) const;
//////////////////////////////////////////////////////////////////////////////////
// ReadTileData helper functions //
//////////////////////////////////////////////////////////////////////////////////
/**
Returns the geo transform from raster space to projection coordinates as defined
by GDAL.
If the transform is not available, the function returns a transform to map
the pixel coordinates to cover the whole geodetic lat long space.
*/
std::array<double, 6> getGeoTransform() const;
PixelCoordinate geodeticToPixel(const Geodetic2& geo) const;
Geodetic2 pixelToGeodetic(const PixelCoordinate& p) const;
IODescription getIODescription(const TileIndex& tileIndex) const;
char* readImageData(IODescription& io, CPLErr& worstError) const;
CPLErr rasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst) const;
CPLErr repeatedRasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst, int depth = 0) const;
std::shared_ptr<TileMetaData> getTileMetaData(std::shared_ptr<RawTile> result, const PixelRegion& region) const;
CPLErr postProcessErrorCheck(std::shared_ptr<const RawTile> ioResult, const IODescription& io) const;
//////////////////////////////////////////////////////////////////////////////////
// Member variables //
//////////////////////////////////////////////////////////////////////////////////
// init data
struct InitData {
std::string initDirectory;
std::string gdalDatasetDesc;
int minimumPixelSize;
GLuint dataType;
} _initData;
struct Cached {
int _maxLevel = -1;
double _tileLevelDifference;
} _cached;
const Configuration _config;
GDALDataset* _dataset;
TileDepthTransform _depthTransform;
TileDataLayout _dataLayout;
static bool GdalHasBeenInitialized;
bool hasBeenInitialized;
};
static bool GdalHasBeenInitialized;
bool hasBeenInitialized;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_DATASET_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATASET_H__

View File

@@ -22,7 +22,6 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tiledatatype.h>
#include <ogr_featurestyle.h>
@@ -46,145 +45,238 @@ namespace {
namespace openspace {
namespace globebrowsing {
float TileDataType::interpretFloat(GDALDataType gdalType, const char* src) {
switch (gdalType) {
case GDT_Byte: return static_cast<float>(*reinterpret_cast<const GLubyte*>(src));
case GDT_UInt16: return static_cast<float>(*reinterpret_cast<const GLushort*>(src));
case GDT_Int16: return static_cast<float>(*reinterpret_cast<const GLshort*>(src));
case GDT_UInt32: return static_cast<float>(*reinterpret_cast<const GLuint*>(src));
case GDT_Int32: return static_cast<float>(*reinterpret_cast<const GLint*>(src));
case GDT_Float32: return static_cast<float>(*reinterpret_cast<const GLfloat*>(src));
case GDT_Float64: return static_cast<float>(*reinterpret_cast<const GLdouble*>(src));
float TileDataType::interpretFloat(GDALDataType gdalType, const char* src) {
switch (gdalType) {
case GDT_Byte:
return static_cast<float>(*reinterpret_cast<const GLubyte*>(src));
case GDT_UInt16:
return static_cast<float>(*reinterpret_cast<const GLushort*>(src));
case GDT_Int16:
return static_cast<float>(*reinterpret_cast<const GLshort*>(src));
case GDT_UInt32:
return static_cast<float>(*reinterpret_cast<const GLuint*>(src));
case GDT_Int32:
return static_cast<float>(*reinterpret_cast<const GLint*>(src));
case GDT_Float32:
return static_cast<float>(*reinterpret_cast<const GLfloat*>(src));
case GDT_Float64:
return static_cast<float>(*reinterpret_cast<const GLdouble*>(src));
default:
LERROR("Unknown data type");
ghoul_assert(false, "Unknown data type");
return -1.0;
}
}
}
size_t TileDataType::numberOfBytes(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte: return sizeof(GLubyte);
case GDT_UInt16: return sizeof(GLushort);
case GDT_Int16: return sizeof(GLshort);
case GDT_UInt32: return sizeof(GLuint);
case GDT_Int32: return sizeof(GLint);
case GDT_Float32: return sizeof(GLfloat);
case GDT_Float64: return sizeof(GLdouble);
size_t TileDataType::numberOfBytes(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte:
return sizeof(GLubyte);
case GDT_UInt16:
return sizeof(GLushort);
case GDT_Int16:
return sizeof(GLshort);
case GDT_UInt32:
return sizeof(GLuint);
case GDT_Int32:
return sizeof(GLint);
case GDT_Float32:
return sizeof(GLfloat);
case GDT_Float64:
return sizeof(GLdouble);
default:
LERROR("Unknown data type");
ghoul_assert(false, "Unknown data type");
return -1;
}
}
size_t TileDataType::getMaximumValue(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte: return 1 << 8;
case GDT_UInt16: return 1 << 16;
case GDT_Int16: return 1 << 15;
case GDT_UInt32: return 1 << 32;
case GDT_Int32: return 1 << 31;
}
}
size_t TileDataType::getMaximumValue(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte:
return 1 << 8;
case GDT_UInt16:
return 1 << 16;
case GDT_Int16:
return 1 << 15;
case GDT_UInt32:
return 1 << 32;
case GDT_Int32:
return 1 << 31;
default:
LERROR("Unknown data type");
return -1;
}
ghoul_assert(false, "Unknown data type");
}
}
TextureFormat TileDataType::getTextureFormat(
int rasterCount, GDALDataType gdalType)
{
TextureFormat format;
TextureFormat TileDataType::getTextureFormat(
int rasterCount, GDALDataType gdalType)
{
TextureFormat format;
switch (rasterCount) {
switch (rasterCount) {
case 1: // Red
format.ghoulFormat = Texture::Format::Red;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_R8; break;
case GDT_UInt16: format.glFormat = GL_R16UI; break;
case GDT_Int16: format.glFormat = GL_R16_SNORM; break;
case GDT_UInt32: format.glFormat = GL_R32UI; break;
case GDT_Int32: format.glFormat = GL_R32I; break;
case GDT_Float32: format.glFormat = GL_R32F; break;
//case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float?
default: LERROR("GDAL data type unknown to OpenGL: " << gdalType);
case GDT_Byte:
format.glFormat = GL_R8;
break;
case GDT_UInt16:
format.glFormat = GL_R16UI;
break;
case GDT_Int16:
format.glFormat = GL_R16_SNORM;
break;
case GDT_UInt32:
format.glFormat = GL_R32UI;
break;
case GDT_Int32:
format.glFormat = GL_R32I;
break;
case GDT_Float32:
format.glFormat = GL_R32F;
break;
// No representation of 64 bit float?
//case GDT_Float64:
// format.glFormat = GL_RED;
// break;
default:
LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 2:
format.ghoulFormat = Texture::Format::RG;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_RG8; break;
case GDT_UInt16: format.glFormat = GL_RG16UI; break;
case GDT_Int16: format.glFormat = GL_RG16_SNORM; break;
case GDT_UInt32: format.glFormat = GL_RG32UI; break;
case GDT_Int32: format.glFormat = GL_RG32I; break;
case GDT_Float32: format.glFormat = GL_RG32F; break;
case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float?
default: LERROR("GDAL data type unknown to OpenGL: " << gdalType);
case GDT_Byte:
format.glFormat = GL_RG8;
break;
case GDT_UInt16:
format.glFormat = GL_RG16UI;
break;
case GDT_Int16:
format.glFormat = GL_RG16_SNORM;
break;
case GDT_UInt32:
format.glFormat = GL_RG32UI;
break;
case GDT_Int32:
format.glFormat = GL_RG32I;
break;
case GDT_Float32:
format.glFormat = GL_RG32F;
break;
case GDT_Float64:
format.glFormat = GL_RED;
break;
default:
LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 3:
format.ghoulFormat = Texture::Format::RGB;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_RGB8; break;
case GDT_UInt16: format.glFormat = GL_RGB16UI; break;
case GDT_Int16: format.glFormat = GL_RGB16_SNORM; break;
case GDT_UInt32: format.glFormat = GL_RGB32UI; break;
case GDT_Int32: format.glFormat = GL_RGB32I; break;
case GDT_Float32: format.glFormat = GL_RGB32F; break;
// case GDT_Float64: format.glFormat = GL_RED; break;// No representation of 64 bit float?
default: LERROR("GDAL data type unknown to OpenGL: " << gdalType);
case GDT_Byte:
format.glFormat = GL_RGB8;
break;
case GDT_UInt16:
format.glFormat = GL_RGB16UI;
break;
case GDT_Int16:
format.glFormat = GL_RGB16_SNORM;
break;
case GDT_UInt32:
format.glFormat = GL_RGB32UI;
break;
case GDT_Int32:
format.glFormat = GL_RGB32I;
break;
case GDT_Float32:
format.glFormat = GL_RGB32F;
break;
// No representation of 64 bit float?
//case GDT_Float64:
// format.glFormat = GL_RED;
// break;
default:
LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 4:
format.ghoulFormat = Texture::Format::RGBA;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_RGBA8; break;
case GDT_UInt16: format.glFormat = GL_RGBA16UI; break;
case GDT_Int16: format.glFormat = GL_RGB16_SNORM; break;
case GDT_UInt32: format.glFormat = GL_RGBA32UI; break;
case GDT_Int32: format.glFormat = GL_RGBA32I; break;
case GDT_Float32: format.glFormat = GL_RGBA32F; break;
case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float?
default: LERROR("GDAL data type unknown to OpenGL: " << gdalType);
case GDT_Byte:
format.glFormat = GL_RGBA8;
break;
case GDT_UInt16:
format.glFormat = GL_RGBA16UI;
break;
case GDT_Int16:
format.glFormat = GL_RGB16_SNORM;
break;
case GDT_UInt32:
format.glFormat = GL_RGBA32UI;
break;
case GDT_Int32:
format.glFormat = GL_RGBA32I;
break;
case GDT_Float32:
format.glFormat = GL_RGBA32F;
break;
// No representation of 64 bit float?
//case GDT_Float64:
// format.glFormat = GL_RED;
// break;
default:
LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
default:
LERROR("Unknown number of channels for OpenGL texture: " << rasterCount);
break;
}
return format;
}
return format;
}
GLuint TileDataType::getOpenGLDataType(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte: return GL_UNSIGNED_BYTE;
case GDT_UInt16: return GL_UNSIGNED_SHORT;
case GDT_Int16: return GL_SHORT;
case GDT_UInt32: return GL_UNSIGNED_INT;
case GDT_Int32: return GL_INT;
case GDT_Float32: return GL_FLOAT;
case GDT_Float64: return GL_DOUBLE;
GLuint TileDataType::getOpenGLDataType(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte:
return GL_UNSIGNED_BYTE;
case GDT_UInt16:
return GL_UNSIGNED_SHORT;
case GDT_Int16:
return GL_SHORT;
case GDT_UInt32:
return GL_UNSIGNED_INT;
case GDT_Int32:
return GL_INT;
case GDT_Float32:
return GL_FLOAT;
case GDT_Float64:
return GL_DOUBLE;
default:
LERROR("GDAL data type unknown to OpenGL: " << gdalType);
return GL_UNSIGNED_BYTE;
}
}
}
GDALDataType TileDataType::getGdalDataType(GLuint glType) {
switch (glType) {
case GL_UNSIGNED_BYTE: return GDT_Byte;
case GL_UNSIGNED_SHORT: return GDT_UInt16;
case GL_SHORT: return GDT_Int16;
case GL_UNSIGNED_INT: return GDT_UInt32;
case GL_INT: return GDT_Int32;
case GL_FLOAT: return GDT_Float32;
case GL_DOUBLE: return GDT_Float64;
GDALDataType TileDataType::getGdalDataType(GLuint glType) {
switch (glType) {
case GL_UNSIGNED_BYTE:
return GDT_Byte;
case GL_UNSIGNED_SHORT:
return GDT_UInt16;
case GL_SHORT:
return GDT_Int16;
case GL_UNSIGNED_INT:
return GDT_UInt32;
case GL_INT:
return GDT_Int32;
case GL_FLOAT:
return GDT_Float32;
case GL_DOUBLE:
return GDT_Float64;
default:
LERROR("OpenGL data type unknown to GDAL: " << glType);
return GDT_Unknown;
}
}
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,57 +1,54 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_DATA_TYPE_H__
#define __TILE_DATA_TYPE_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATA_TYPE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATA_TYPE_H__
#include <ghoul/opengl/texture.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tile.h>
#include "gdal_priv.h"
#include <ghoul/opengl/ghoul_gl.h>
#include <gdal.h>
namespace openspace {
namespace globebrowsing {
struct TileDataType {
struct TileDataType {
static GLuint getOpenGLDataType(GDALDataType gdalType);
static GLuint getOpenGLDataType(GDALDataType gdalType);
static GDALDataType getGdalDataType(GLuint glType);
static GDALDataType getGdalDataType(GLuint glType);
static TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType);
static TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType);
static size_t getMaximumValue(GDALDataType gdalType);
static size_t getMaximumValue(GDALDataType gdalType);
static size_t numberOfBytes(GDALDataType gdalType);
static size_t numberOfBytes(GDALDataType gdalType);
static float interpretFloat(GDALDataType gdalType, const char* src);
};
static float interpretFloat(GDALDataType gdalType, const char* src);
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_DATA_TYPE_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATA_TYPE_H__

View File

@@ -1,122 +1,115 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tilediskcache.h>
#include <modules/globebrowsing/tile/tile.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <sstream>
#include <fstream>
#include <algorithm>
namespace {
const std::string _loggerCat = "TileDiskCache";
}
using namespace ghoul::filesystem;
namespace openspace {
namespace globebrowsing {
const std::string TileDiskCache::CACHE_ROOT = "tilecache";
const std::string TileDiskCache::CACHE_ROOT = "tilecache";
TileDiskCache::TileDiskCache(const std::string& name)
: _name(name)
{
if (!FileSystem::isInitialized()) {
FileSystem::initialize();
}
std::string pathToCacheDir = FileSys.pathByAppendingComponent(CACHE_ROOT, name);
Directory cacheDir(pathToCacheDir, Directory::RawPath::No);
if (!FileSys.directoryExists(cacheDir)) {
FileSys.createDirectory(pathToCacheDir, FileSystem::Recursive::Yes);
}
_cacheDir = cacheDir;
TileDiskCache::TileDiskCache(const std::string& name)
: _name(name)
{
std::string pathToCacheDir = FileSys.pathByAppendingComponent(CACHE_ROOT, name);
Directory cacheDir(pathToCacheDir, Directory::RawPath::No);
if (!FileSys.directoryExists(cacheDir)) {
FileSys.createDirectory(pathToCacheDir, FileSystem::Recursive::Yes);
}
_cacheDir = cacheDir;
}
bool TileDiskCache::has(const TileIndex& tileIndex) const {
File metaFile = getMetaDataFile(tileIndex);
return FileSys.fileExists(metaFile);
bool TileDiskCache::has(const TileIndex& tileIndex) const {
File metaFile = getMetaDataFile(tileIndex);
return FileSys.fileExists(metaFile);
}
std::shared_ptr<RawTile> TileDiskCache::get(const TileIndex& tileIndex) {
File metaDataFile = getMetaDataFile(tileIndex);
File dataFile = getDataFile(tileIndex);
if (FileSys.fileExists(metaDataFile) && FileSys.fileExists(dataFile)) {
// read meta
std::ifstream ifsMeta;
ifsMeta.open(metaDataFile.path(), std::ifstream::in);
RawTile res = RawTile::deserializeMetaData(ifsMeta);
ifsMeta.close();
// read data
std::ifstream ifsData;
ifsData.open(dataFile.path(), std::ifstream::binary);
char * buffer = new char[res.nBytesImageData];
ifsData.read(buffer, res.nBytesImageData);
res.imageData = buffer;
return std::make_shared<RawTile>(res);
}
return nullptr;
}
std::shared_ptr<RawTile> TileDiskCache::get(const TileIndex& tileIndex) {
File metaDataFile = getMetaDataFile(tileIndex);
bool TileDiskCache::put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile) {
File metaDataFile = getMetaDataFile(tileIndex);
if (!FileSys.fileExists(metaDataFile)) {
std::ofstream ofsMeta;
ofsMeta.open(metaDataFile.path());
rawTile->serializeMetaData(ofsMeta);
ofsMeta.close();
std::ofstream ofsData;
File dataFile = getDataFile(tileIndex);
if (FileSys.fileExists(metaDataFile) && FileSys.fileExists(dataFile)) {
// read meta
std::ifstream ifsMeta;
ifsMeta.open(metaDataFile.path(), std::ifstream::in);
RawTile res = RawTile::deserializeMetaData(ifsMeta);
ifsMeta.close();
// read data
std::ifstream ifsData;
ifsData.open(dataFile.path(), std::ifstream::binary);
char * buffer = new char[res.nBytesImageData];
ifsData.read(buffer, res.nBytesImageData);
res.imageData = buffer;
return std::make_shared<RawTile>(res);
}
return nullptr;
ofsData.open(dataFile.path(), std::ofstream::binary);
char* data = (char*)rawTile->imageData;
ofsData.write(data, rawTile->nBytesImageData);
ofsData.close();
return true;
}
return false;
}
bool TileDiskCache::put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile) {
File metaDataFile = getMetaDataFile(tileIndex);
if (!FileSys.fileExists(metaDataFile)) {
std::ofstream ofsMeta;
ofsMeta.open(metaDataFile.path());
rawTile->serializeMetaData(ofsMeta);
ofsMeta.close();
std::string TileDiskCache::getFilePath(const TileIndex& tileIndex) const {
std::stringstream ss;
ss << tileIndex.level;
ss << "_" << tileIndex.x;
ss << "_" << tileIndex.y;
std::string filePath = FileSys.pathByAppendingComponent(_cacheDir.path(), ss.str());
return filePath;
}
std::ofstream ofsData;
File dataFile = getDataFile(tileIndex);
ofsData.open(dataFile.path(), std::ofstream::binary);
char * data = (char*)rawTile->imageData;
ofsData.write(data, rawTile->nBytesImageData);
ofsData.close();
return true;
}
return false;
}
File TileDiskCache::getMetaDataFile(const TileIndex& tileIndex) const {
return File(getFilePath(tileIndex) + ".meta");
}
std::string TileDiskCache::getFilePath(const TileIndex& tileIndex) const {
std::stringstream ss;
ss << tileIndex.level;
ss << "_" << tileIndex.x;
ss << "_" << tileIndex.y;
std::string filePath = FileSys.pathByAppendingComponent(_cacheDir.path(), ss.str());
return filePath;
}
File TileDiskCache::getMetaDataFile(const TileIndex& tileIndex) const {
return File(getFilePath(tileIndex) + ".meta");
}
File TileDiskCache::getDataFile(const TileIndex& tileIndex) const {
return File(getFilePath(tileIndex) + ".data");
}
File TileDiskCache::getDataFile(const TileIndex& tileIndex) const {
return File(getFilePath(tileIndex) + ".data");
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,64 +1,63 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_DISK_CACHE_H__
#define __TILE_DISK_CACHE_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DISK_CACHE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DISK_CACHE_H__
#include <modules/globebrowsing/tile/tileindex.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <ghoul/filesystem/directory.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem>
#include <memory>
namespace openspace {
namespace globebrowsing {
struct TileIndex;
struct RawTile;
using namespace ghoul::filesystem;
class TileDiskCache {
public:
TileDiskCache(const std::string& name);
class TileDiskCache {
public:
TileDiskCache(const std::string& name);
std::shared_ptr<RawTile> get(const TileIndex& tileIndex);
bool has(const TileIndex& tileIndex) const;
bool put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile);
std::shared_ptr<RawTile> get(const TileIndex& tileIndex);
bool has(const TileIndex& tileIndex) const;
bool put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile);
static const std::string CACHE_ROOT;
static const std::string CACHE_ROOT;
private:
const std::string _name;
private:
const std::string _name;
Directory _cacheDir;
ghoul::filesystem::Directory _cacheDir;
std::string getFilePath(const TileIndex& tileIndex) const;
File getMetaDataFile(const TileIndex& tileIndex) const;
File getDataFile(const TileIndex& tileIndex) const;
std::string getFilePath(const TileIndex& tileIndex) const;
ghoul::filesystem::File getMetaDataFile(const TileIndex& tileIndex) const;
ghoul::filesystem::File getDataFile(const TileIndex& tileIndex) const;
};
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_DISK_CACHE_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DISK_CACHE_H__

View File

@@ -23,144 +23,138 @@
****************************************************************************************/
#include <modules/globebrowsing/tile/tileindex.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <ghoul/misc/dictionary.h>
#include <sstream>
namespace {
const std::string _loggerCat = "TileIndex";
const std::string KeyLevel = "Level";
const std::string KeyX = "X";
const std::string KeyY = "Y";
const char* KeyLevel = "Level";
const char* KeyX = "X";
const char* KeyY = "Y";
}
namespace openspace {
namespace globebrowsing {
/**
Creates the geodetic tile index for the Geodetic patch that covers the
point p at the specified level
*/
TileIndex::TileIndex(const Geodetic2& point, int level)
: level(level) {
int numIndicesAtLevel = 1 << level;
double u = 0.5 + point.lon / (2 * M_PI);
double v = 0.25 - point.lat / (2 * M_PI);
double xIndexSpace = u * numIndicesAtLevel;
double yIndexSpace = v * numIndicesAtLevel;
TileIndex::TileIndex(int x, int y, int level)
: x(x), y(y), level(level)
{}
x = floor(xIndexSpace);
y = floor(yIndexSpace);
}
TileIndex::TileIndex(const TileIndex& other)
: x(other.x), y(other.y), level(other.level)
{}
/**
* Initializes a TileIndex from a Dictionary
*/
TileIndex::TileIndex(const ghoul::Dictionary& dict){
level = static_cast<int>(dict.value<double>(KeyLevel));
x = static_cast<int>(dict.value<double>(KeyX));
y = static_cast<int>(dict.value<double>(KeyY));
}
TileIndex::TileIndex(const Geodetic2& point, int level)
: level(level)
{
int numIndicesAtLevel = 1 << level;
double u = 0.5 + point.lon / (2 * glm::pi<double>());
double v = 0.25 - point.lat / (2 * glm::pi<double>());
double xIndexSpace = u * numIndicesAtLevel;
double yIndexSpace = v * numIndicesAtLevel;
TileIndex TileIndex::child(Quad q) const {
return TileIndex(2 * x + q % 2, 2 * y + q / 2, level + 1);
}
x = floor(xIndexSpace);
y = floor(yIndexSpace);
}
TileIndex TileIndex::parent() const {
//ghoul_assert(level > 0, "tile at level 0 has no parent!");
return TileIndex(x / 2, y / 2, level - 1);
}
TileIndex::TileIndex(const ghoul::Dictionary& dict) {
level = static_cast<int>(dict.value<double>(KeyLevel));
x = static_cast<int>(dict.value<double>(KeyX));
y = static_cast<int>(dict.value<double>(KeyY));
}
TileIndex& TileIndex::operator--() {
x /= 2;
y /= 2;
level--;
return *this;
}
TileIndex TileIndex::child(Quad q) const {
return TileIndex(2 * x + q % 2, 2 * y + q / 2, level + 1);
}
TileIndex TileIndex::operator--(int) {
TileIndex tmp(*this);
--(*this);
return tmp;
}
TileIndex TileIndex::parent() const {
//ghoul_assert(level > 0, "tile at level 0 has no parent!");
return TileIndex(x / 2, y / 2, level - 1);
}
TileIndex& TileIndex::operator-=(unsigned int levels) {
x <<= levels;
y <<= levels;
level -= levels;
return *this;
}
TileIndex& TileIndex::operator--() {
x /= 2;
y /= 2;
level--;
return *this;
}
TileIndex TileIndex::operator--(int) {
TileIndex tmp(*this);
--(*this);
return tmp;
}
glm::vec2 TileIndex::positionRelativeParent() const{
// In OpenGL, positive y direction is up
return glm::vec2(isEastChild() ? 0.5 : 0, isNorthChild() ? 0.5 : 0);
}
TileIndex& TileIndex::operator-=(unsigned int levels) {
x <<= levels;
y <<= levels;
level -= levels;
return *this;
}
/**
Gets the tile at a specified offset from this tile.
Accepts delta indices ranging from [-2^level, Infinity[
*/
TileIndex TileIndex::getRelatedTile(int deltaX, int deltaY) const {
int indicesAtThisLevel = 1 << level;
int newX = (indicesAtThisLevel + x + deltaX) % indicesAtThisLevel;
int newY = (indicesAtThisLevel + y + deltaY) % indicesAtThisLevel;
return TileIndex(newX, newY, level);
}
glm::vec2 TileIndex::positionRelativeParent() const {
// In OpenGL, positive y direction is up
return glm::vec2(isEastChild() ? 0.5 : 0, isNorthChild() ? 0.5 : 0);
}
int TileIndex::manhattan(const TileIndex& other) const {
ghoul_assert(level == other.level, "makes no sense if not on same level");
return std::abs(x - other.x) + std::abs(y - other.y);
}
TileIndex TileIndex::getRelatedTile(int deltaX, int deltaY) const {
int indicesAtThisLevel = 1 << level;
int newX = (indicesAtThisLevel + x + deltaX) % indicesAtThisLevel;
int newY = (indicesAtThisLevel + y + deltaY) % indicesAtThisLevel;
return TileIndex(newX, newY, level);
}
/**
Creates a hash which can be used as key in hash maps.
int TileIndex::manhattan(const TileIndex& other) const {
ghoul_assert(level == other.level, "makes no sense if not on same level");
return std::abs(x - other.x) + std::abs(y - other.y);
}
/**
Creates a hash which can be used as key in hash maps.
+-------+------------+-------+------------+
| USAGE | BIT RANGE | #BITS | MAX VALUE |
+-------+------------+-------+------------+
| level | 0 - 5 | 5 | 31 |
| x | 5 - 35 | 30 | 1073741824 |
| y | 35 - 64 | 29 | 536870912 |
+-------+------------+-------+------------+
+-------+------------+-------+------------+
| USAGE | BIT RANGE | #BITS | MAX VALUE |
+-------+------------+-------+------------+
| level | 0 - 5 | 5 | 31 |
| x | 5 - 35 | 30 | 1073741824 |
| y | 35 - 64 | 29 | 536870912 |
+-------+------------+-------+------------+
*/
TileHashKey TileIndex::hashKey() const {
TileHashKey key = 0LL;
key |= level;
key |= x << 5;
key |= ((TileHashKey)y) << 35;
return key;
}
*/
TileHashKey TileIndex::hashKey() const {
TileHashKey key = 0LL;
key |= level;
key |= x << 5;
key |= ((TileHashKey)y) << 35;
return key;
}
std::string TileIndex::toString() const {
std::stringstream ss;
for (int i = level; i > 0; i--){
char digit = '0';
int mask = 1 << (i - 1);
if ((x & mask) != 0) {
digit++;
}
if ((y & mask) != 0) {
digit++;
digit++;
}
ss << digit;
std::string TileIndex::toString() const {
std::stringstream ss;
for (int i = level; i > 0; i--) {
char digit = '0';
int mask = 1 << (i - 1);
if ((x & mask) != 0) {
digit++;
}
return ss.str();
if ((y & mask) != 0) {
digit++;
digit++;
}
ss << digit;
}
return ss.str();
}
bool TileIndex::operator==(const TileIndex& other) const {
return x == other.x && y == other.y && level == other.level;
}
bool TileIndex::operator==(const TileIndex& other) const {
return x == other.x && y == other.y && level == other.level;
}
std::ostream& operator<<(std::ostream& os, const TileIndex& ci) {
os << "{ x = " << ci.x << ", y = " << ci.y << ", level = " << ci.level << " }";
return os;
}
std::ostream& operator<<(std::ostream& os, const TileIndex& ci) {
os << "{ x = " << ci.x << ", y = " << ci.y << ", level = " << ci.level << " }";
return os;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -22,13 +22,10 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_INDEX_H__
#define __TILE_INDEX_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_INDEX_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_INDEX_H__
#include <glm/glm.hpp>
#include <string>
#include <vector>
#include <ghoul/glm.h>
#include <stdint.h>
namespace ghoul {
@@ -59,10 +56,18 @@ using TileHashKey = uint64_t;
struct TileIndex {
int x, y, level;
TileIndex() : x(0), y(0), level(0) { }
TileIndex(int x, int y, int level) : x(x), y(y), level(level) { }
TileIndex(const TileIndex& other) : x(other.x), y(other.y), level(other.level) { }
TileIndex(int x = 0, int y = 0, int level = 0);
TileIndex(const TileIndex& other);
/**
* Creates the geodetic tile index for the Geodetic patch that covers the
* point p at the specified level
*/
TileIndex(const Geodetic2& point, int level);
/**
* Initializes a TileIndex from a Dictionary
*/
TileIndex(const ghoul::Dictionary& dict);
@@ -101,9 +106,9 @@ struct TileIndex {
std::string toString() const;
/**
Gets the tile at a specified offset from this tile.
Accepts delta indices ranging from [-2^level, Infinity[
*/
* Gets the tile at a specified offset from this tile.
* Accepts delta indices ranging from [-2^level, Infinity[
*/
TileIndex getRelatedTile(int deltaX, int deltaY) const;
int manhattan(const TileIndex& other) const;
@@ -118,4 +123,4 @@ std::ostream& operator<<(std::ostream& os, const TileIndex& ti);
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_INDEX_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_INDEX_H__

View File

@@ -1,51 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tilepile.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/tileselector.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/opengl/textureunit.h>
#include <ghoul/logging/logmanager.h>
namespace {
const std::string _loggerCat = "TilePile";
}
namespace openspace {
namespace globebrowsing {
/*
void TilePile::update(TileProvider* tileProvider, const TileIndex& tileIndex){
}
void TilePile::bind(ProgramObject* programObject){
}*/
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,29 +1,29 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILEPILE_H__
#define __TILEPILE_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILEPILE_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILEPILE_H__
#include <ghoul/opengl/texture.h> // Texture
@@ -51,4 +51,4 @@ namespace globebrowsing {
#endif // __TILEPILE_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILEPILE_H__

View File

@@ -1,39 +1,37 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/filesystem/filesystem.h>
#include <modules/globebrowsing/tile/asynctilereader.h>
#include <modules/globebrowsing/tile/tiledataset.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/engine/openspaceengine.h>
#include <ghoul/misc/dictionary.h>
namespace {
const std::string _loggerCat = "CachingTileProvider";
const char* _loggerCat = "CachingTileProvider";
const char* KeyDoPreProcessing = "DoPreProcessing";
const char* KeyMinimumPixelSize = "MinimumPixelSize";
@@ -45,187 +43,187 @@ namespace {
namespace openspace {
namespace globebrowsing {
CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary)
CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary)
: _framesSinceLastRequestFlush(0)
{
std::string name = "Name unspecified";
dictionary.getValue("Name", name);
std::string _loggerCat = "CachingTileProvider : " + name;
{
std::string name = "Name unspecified";
dictionary.getValue("Name", name);
std::string _loggerCat = "CachingTileProvider : " + name;
// 1. Get required Keys
std::string filePath;
if (!dictionary.getValue<std::string>(KeyFilePath, filePath)) {
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
}
// 2. Initialize default values for any optional Keys
TileDataset::Configuration config;
config.doPreProcessing = false;
config.minimumTilePixelSize = 512;
// getValue does not work for integers
double minimumPixelSize;
double cacheSize = 512;
double framesUntilRequestFlush = 60;
// 3. Check for used spcified optional keys
if (dictionary.getValue<bool>(KeyDoPreProcessing, config.doPreProcessing)) {
LDEBUG("Default doPreProcessing overridden: " << config.doPreProcessing);
}
if (dictionary.getValue<double>(KeyMinimumPixelSize, minimumPixelSize)) {
LDEBUG("Default minimumPixelSize overridden: " << minimumPixelSize);
config.minimumTilePixelSize = static_cast<int>(minimumPixelSize);
}
if (dictionary.getValue<double>(KeyCacheSize, cacheSize)) {
LDEBUG("Default cacheSize overridden: " << cacheSize);
}
if (dictionary.getValue<double>(KeyFlushInterval, framesUntilRequestFlush)) {
LDEBUG("Default framesUntilRequestFlush overridden: " <<
framesUntilRequestFlush);
}
// Initialize instance variables
auto tileDataset = std::make_shared<TileDataset>(filePath, config);
// only one thread per provider supported atm
// (GDAL does not handle multiple threads for a single dataset very well
// currently)
auto threadPool = std::make_shared<ThreadPool>(1);
_asyncTextureDataProvider = std::make_shared<AsyncTileDataProvider>(
tileDataset, threadPool);
_tileCache = std::make_shared<TileCache>(cacheSize);
_framesUntilRequestFlush = framesUntilRequestFlush;
// 1. Get required Keys
std::string filePath;
if (!dictionary.getValue<std::string>(KeyFilePath, filePath)) {
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
}
CachingTileProvider::CachingTileProvider(
std::shared_ptr<AsyncTileDataProvider> tileReader,
std::shared_ptr<TileCache> tileCache,
int framesUntilFlushRequestQueue)
: _asyncTextureDataProvider(tileReader)
, _tileCache(tileCache)
, _framesUntilRequestFlush(framesUntilFlushRequestQueue)
, _framesSinceLastRequestFlush(0)
{
// 2. Initialize default values for any optional Keys
TileDataset::Configuration config;
config.doPreProcessing = false;
config.minimumTilePixelSize = 512;
// getValue does not work for integers
double minimumPixelSize;
double cacheSize = 512;
double framesUntilRequestFlush = 60;
// 3. Check for used spcified optional keys
if (dictionary.getValue<bool>(KeyDoPreProcessing, config.doPreProcessing)) {
LDEBUG("Default doPreProcessing overridden: " << config.doPreProcessing);
}
if (dictionary.getValue<double>(KeyMinimumPixelSize, minimumPixelSize)) {
LDEBUG("Default minimumPixelSize overridden: " << minimumPixelSize);
config.minimumTilePixelSize = static_cast<int>(minimumPixelSize);
}
if (dictionary.getValue<double>(KeyCacheSize, cacheSize)) {
LDEBUG("Default cacheSize overridden: " << cacheSize);
}
if (dictionary.getValue<double>(KeyFlushInterval, framesUntilRequestFlush)) {
LDEBUG("Default framesUntilRequestFlush overridden: " <<
framesUntilRequestFlush);
}
CachingTileProvider::~CachingTileProvider(){
// Initialize instance variables
auto tileDataset = std::make_shared<TileDataset>(filePath, config);
// only one thread per provider supported atm
// (GDAL does not handle multiple threads for a single dataset very well
// currently)
auto threadPool = std::make_shared<ThreadPool>(1);
_asyncTextureDataProvider = std::make_shared<AsyncTileDataProvider>(
tileDataset, threadPool);
_tileCache = std::make_shared<TileCache>(static_cast<size_t>(cacheSize));
_framesUntilRequestFlush = framesUntilRequestFlush;
}
CachingTileProvider::CachingTileProvider(
std::shared_ptr<AsyncTileDataProvider> tileReader,
std::shared_ptr<TileCache> tileCache,
int framesUntilFlushRequestQueue)
: _asyncTextureDataProvider(tileReader)
, _tileCache(tileCache)
, _framesUntilRequestFlush(framesUntilFlushRequestQueue)
, _framesSinceLastRequestFlush(0)
{}
CachingTileProvider::~CachingTileProvider(){
clearRequestQueue();
}
void CachingTileProvider::update() {
initTexturesFromLoadedData();
if (_framesSinceLastRequestFlush++ > _framesUntilRequestFlush) {
clearRequestQueue();
}
}
void CachingTileProvider::update() {
initTexturesFromLoadedData();
if (_framesSinceLastRequestFlush++ > _framesUntilRequestFlush) {
clearRequestQueue();
}
}
void CachingTileProvider::reset() {
_tileCache->clear();
_asyncTextureDataProvider->reset();
}
void CachingTileProvider::reset() {
_tileCache->clear();
_asyncTextureDataProvider->reset();
}
int CachingTileProvider::maxLevel() {
return _asyncTextureDataProvider->getTextureDataProvider()->maxChunkLevel();
}
int CachingTileProvider::maxLevel() {
return _asyncTextureDataProvider->getTextureDataProvider()->maxChunkLevel();
}
Tile CachingTileProvider::getTile(const TileIndex& tileIndex) {
Tile tile = Tile::TileUnavailable;
Tile CachingTileProvider::getTile(const TileIndex& tileIndex) {
Tile tile = Tile::TileUnavailable;
if (tileIndex.level > maxLevel()) {
tile.status = Tile::Status::OutOfRange;
return tile;
}
TileHashKey key = tileIndex.hashKey();
if (_tileCache->exist(key)) {
return _tileCache->get(key);
}
else {
_asyncTextureDataProvider->enqueueTileIO(tileIndex);
}
if (tileIndex.level > maxLevel()) {
tile.status = Tile::Status::OutOfRange;
return tile;
}
float CachingTileProvider::noDataValueAsFloat() {
return _asyncTextureDataProvider->noDataValueAsFloat();
TileHashKey key = tileIndex.hashKey();
if (_tileCache->exist(key)) {
return _tileCache->get(key);
}
Tile CachingTileProvider::getDefaultTile() {
if (_defaultTile.texture == nullptr) {
_defaultTile = createTile(_asyncTextureDataProvider->getTextureDataProvider()->defaultTileData());
}
return _defaultTile;
else {
_asyncTextureDataProvider->enqueueTileIO(tileIndex);
}
return tile;
}
void CachingTileProvider::initTexturesFromLoadedData() {
auto rawTiles = _asyncTextureDataProvider->getRawTiles();
for(auto rawTile : rawTiles){
TileHashKey key = rawTile->tileIndex.hashKey();
Tile tile = createTile(rawTile);
_tileCache->put(key, tile);
}
float CachingTileProvider::noDataValueAsFloat() {
return _asyncTextureDataProvider->noDataValueAsFloat();
}
Tile CachingTileProvider::getDefaultTile() {
if (_defaultTile.texture == nullptr) {
_defaultTile = createTile(
_asyncTextureDataProvider->getTextureDataProvider()->defaultTileData()
);
}
return _defaultTile;
}
void CachingTileProvider::clearRequestQueue() {
_asyncTextureDataProvider->clearRequestQueue();
_framesSinceLastRequestFlush = 0;
}
Tile::Status CachingTileProvider::getTileStatus(const TileIndex& tileIndex) {
auto tileDataset = _asyncTextureDataProvider->getTextureDataProvider();
if (tileIndex.level > tileDataset->maxChunkLevel()) {
return Tile::Status::OutOfRange;
}
TileHashKey key = tileIndex.hashKey();
if (_tileCache->exist(key)) {
return _tileCache->get(key).status;
}
return Tile::Status::Unavailable;
}
TileDepthTransform CachingTileProvider::depthTransform() {
return _asyncTextureDataProvider->getTextureDataProvider()->getDepthTransform();
}
Tile CachingTileProvider::createTile(std::shared_ptr<RawTile> rawTile) {
if (rawTile->error != CE_None) {
return{ nullptr, nullptr, Tile::Status::IOError };
}
void CachingTileProvider::initTexturesFromLoadedData() {
auto rawTiles = _asyncTextureDataProvider->getRawTiles();
for (auto rawTile : rawTiles){
TileHashKey key = rawTile->tileIndex.hashKey();
TileDataLayout dataLayout =
_asyncTextureDataProvider->getTextureDataProvider()->getDataLayout();
// The texture should take ownership of the data
std::shared_ptr<Texture> texture = std::make_shared<Texture>(
rawTile->imageData,
rawTile->dimensions,
dataLayout.textureFormat.ghoulFormat,
dataLayout.textureFormat.glFormat,
dataLayout.glType,
Texture::FilterMode::Linear,
Texture::WrappingMode::ClampToEdge);
texture->uploadTexture();
// AnisotropicMipMap must be set after texture is uploaded. Why?!
texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
Tile tile = {
texture,
rawTile->tileMetaData,
Tile::Status::OK
};
return tile;
Tile tile = createTile(rawTile);
_tileCache->put(key, tile);
}
}
void CachingTileProvider::clearRequestQueue() {
_asyncTextureDataProvider->clearRequestQueue();
_framesSinceLastRequestFlush = 0;
}
Tile::Status CachingTileProvider::getTileStatus(const TileIndex& tileIndex) {
auto tileDataset = _asyncTextureDataProvider->getTextureDataProvider();
if (tileIndex.level > tileDataset->maxChunkLevel()) {
return Tile::Status::OutOfRange;
}
TileHashKey key = tileIndex.hashKey();
if (_tileCache->exist(key)) {
return _tileCache->get(key).status;
}
return Tile::Status::Unavailable;
}
TileDepthTransform CachingTileProvider::depthTransform() {
return _asyncTextureDataProvider->getTextureDataProvider()->getDepthTransform();
}
Tile CachingTileProvider::createTile(std::shared_ptr<RawTile> rawTile) {
if (rawTile->error != CE_None) {
return{ nullptr, nullptr, Tile::Status::IOError };
}
TileHashKey key = rawTile->tileIndex.hashKey();
TileDataLayout dataLayout =
_asyncTextureDataProvider->getTextureDataProvider()->getDataLayout();
// The texture should take ownership of the data
std::shared_ptr<Texture> texture = std::make_shared<Texture>(
rawTile->imageData,
rawTile->dimensions,
dataLayout.textureFormat.ghoulFormat,
dataLayout.textureFormat.glFormat,
dataLayout.glType,
Texture::FilterMode::Linear,
Texture::WrappingMode::ClampToEdge);
texture->uploadTexture();
// AnisotropicMipMap must be set after texture is uploaded. Why?!
texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
Tile tile = {
texture,
rawTile->tileMetaData,
Tile::Status::OK
};
return tile;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,117 +1,98 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CACHING_TILE_PROVIDER_H__
#define __CACHING_TILE_PROVIDER_H__
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // absPath
#include <ghoul/opengl/texture.h>
#include <ghoul/io/texture/texturereader.h>
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CACHING_TILE_PROVIDER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_CACHING_TILE_PROVIDER_H__
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/asynctilereader.h>
#include <modules/globebrowsing/other/lrucache.h>
//////////////////////////////////////////////////////////////////////////////////////////
// TILE PROVIDER //
//////////////////////////////////////////////////////////////////////////////////////////
namespace openspace {
namespace globebrowsing {
/**
* Provides tiles loaded by <code>AsyncTileDataProvider</code> and
* caches them in memory using LRU caching
*/
class CachingTileProvider : public TileProvider {
public:
class AsyncTileDataProvider;
CachingTileProvider(const ghoul::Dictionary& dictionary);
/**
* Provides tiles loaded by <code>AsyncTileDataProvider</code> and
* caches them in memory using LRU caching
*/
class CachingTileProvider : public TileProvider {
public:
CachingTileProvider(const ghoul::Dictionary& dictionary);
CachingTileProvider(
std::shared_ptr<AsyncTileDataProvider> tileReader,
std::shared_ptr<TileCache> tileCache,
int framesUntilFlushRequestQueue);
CachingTileProvider(
std::shared_ptr<AsyncTileDataProvider> tileReader,
std::shared_ptr<TileCache> tileCache,
int framesUntilFlushRequestQueue);
virtual ~CachingTileProvider();
virtual ~CachingTileProvider();
/**
* \returns a Tile with status OK iff it exists in in-memory
* cache. If not, it may enqueue some IO operations on a
* separate thread.
*/
virtual Tile getTile(const TileIndex& tileIndex);
/**
* \returns a Tile with status OK iff it exists in in-memory
* cache. If not, it may enqueue some IO operations on a
* separate thread.
*/
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
virtual float noDataValueAsFloat();
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
virtual float noDataValueAsFloat();
private:
private:
/**
* Collects all asynchronously downloaded <code>RawTile</code>
* and uses <code>createTile</code> to create <code>Tile</code>s,
* which are put in the LRU cache - potentially pushing out outdated
* Tiles.
*/
void initTexturesFromLoadedData();
//////////////////////////////////////////////////////////////////////////////////
// Helper functions //
//////////////////////////////////////////////////////////////////////////////////
/**
* \returns A tile with <code>Tile::Status::OK</code> if no errors
* occured, a tile with <code>Tile::Status::IOError</code> otherwise
*/
Tile createTile(std::shared_ptr<RawTile> res);
/**
* Collects all asynchronously downloaded <code>RawTile</code>
* and uses <code>createTile</code> to create <code>Tile</code>s,
* which are put in the LRU cache - potentially pushing out outdated
* Tiles.
*/
void initTexturesFromLoadedData();
/**
* Deletes all enqueued, but not yet started async downloads of textures.
* Note that this does not cancel any currently ongoing async downloads.
*/
void clearRequestQueue();
/**
* \returns A tile with <code>Tile::Status::OK</code> if no errors
* occured, a tile with <code>Tile::Status::IOError</code> otherwise
*/
Tile createTile(std::shared_ptr<RawTile> res);
std::shared_ptr<AsyncTileDataProvider> _asyncTextureDataProvider;
std::shared_ptr<TileCache> _tileCache;
/**
* Deletes all enqueued, but not yet started async downloads of textures.
* Note that this does not cancel any currently ongoing async downloads.
*/
void clearRequestQueue();
int _framesSinceLastRequestFlush;
int _framesUntilRequestFlush;
//////////////////////////////////////////////////////////////////////////////////
// Member variables //
//////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<AsyncTileDataProvider> _asyncTextureDataProvider;
std::shared_ptr<TileCache> _tileCache;
int _framesSinceLastRequestFlush;
int _framesUntilRequestFlush;
Tile _defaultTile;
};
Tile _defaultTile;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __CACHING_TILE_PROVIDER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CACHING_TILE_PROVIDER_H__

View File

@@ -1,97 +1,90 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/singleimageprovider.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/engine/openspaceengine.h>
#include <ghoul/misc/dictionary.h>
namespace {
const std::string _loggerCat = "SingleImageProvider";
const char* KeyFilePath = "FilePath";
}
namespace openspace {
namespace globebrowsing {
SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) {
// Required input
if (!dictionary.getValue<std::string>(KeyFilePath, _imagePath)) {
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
}
reset();
SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) {
// Required input
if (!dictionary.getValue<std::string>(KeyFilePath, _imagePath)) {
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
}
SingleImageProvider::SingleImageProvider(const std::string& imagePath)
: _imagePath(imagePath)
{
reset();
}
reset();
}
Tile SingleImageProvider::getTile(const TileIndex& tileIndex) {
return _tile;
}
SingleImageProvider::SingleImageProvider(const std::string& imagePath)
: _imagePath(imagePath)
{
reset();
}
Tile SingleImageProvider::getDefaultTile() {
return _tile;
}
Tile SingleImageProvider::getTile(const TileIndex& tileIndex) {
return _tile;
}
Tile::Status SingleImageProvider::getTileStatus(const TileIndex& index) {
return _tile.status;
}
Tile SingleImageProvider::getDefaultTile() {
return _tile;
}
TileDepthTransform SingleImageProvider::depthTransform() {
TileDepthTransform transform;
transform.depthOffset = 0.0f;
transform.depthScale = 1.0f;
return transform;
}
Tile::Status SingleImageProvider::getTileStatus(const TileIndex& index) {
return _tile.status;
}
void SingleImageProvider::update() {
// nothing to be done
}
TileDepthTransform SingleImageProvider::depthTransform() {
TileDepthTransform transform;
transform.depthOffset = 0.0f;
transform.depthScale = 1.0f;
return transform;
}
void SingleImageProvider::reset() {
_tile = Tile();
_tile.texture = std::shared_ptr<Texture>(ghoul::io::TextureReader::ref().loadTexture(_imagePath).release());
_tile.status = _tile.texture != nullptr ? Tile::Status::OK : Tile::Status::IOError;
_tile.metaData = nullptr;
void SingleImageProvider::update() {
// nothing to be done
}
_tile.texture->uploadTexture();
_tile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
}
void SingleImageProvider::reset() {
_tile = Tile();
_tile.texture = std::shared_ptr<Texture>(ghoul::io::TextureReader::ref().loadTexture(_imagePath).release());
_tile.status = _tile.texture != nullptr ? Tile::Status::OK : Tile::Status::IOError;
_tile.metaData = nullptr;
int SingleImageProvider::maxLevel() {
return 1337; // unlimited
}
_tile.texture->uploadTexture();
_tile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
}
int SingleImageProvider::maxLevel() {
return 1337; // unlimited
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,71 +1,57 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __SINGLE_IMAGE_PROVIDER_H__
#define __SINGLE_IMAGE_PROVIDER_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_SINGLE_IMAGE_PROVIDER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_SINGLE_IMAGE_PROVIDER_H__
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/asynctilereader.h>
#include <gdal_priv.h>
#include <openspace/engine/downloadmanager.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // absPath
#include <ghoul/opengl/texture.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/font/fontrenderer.h>
#include <set>
namespace openspace {
namespace globebrowsing {
using namespace ghoul::opengl;
using namespace ghoul::opengl;
class SingleImageProvider : public TileProvider {
public:
SingleImageProvider(const ghoul::Dictionary& dictionary);
SingleImageProvider(const std::string& imagePath);
virtual ~SingleImageProvider() { }
class SingleImageProvider : public TileProvider {
public:
SingleImageProvider(const ghoul::Dictionary& dictionary);
SingleImageProvider(const std::string& imagePath);
virtual ~SingleImageProvider() = default;
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& index);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
private:
Tile _tile;
std::string _imagePath;
};
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& index);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
private:
Tile _tile;
std::string _imagePath;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __SINGLE_IMAGE_PROVIDER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_SINGLE_IMAGE_PROVIDER_H__

View File

@@ -1,47 +1,35 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/geodetic2.h>
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tileprovider/temporaltileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <openspace/engine/downloadmanager.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // abspath
#include <openspace/util/time.h>
#include <string>
#include <fstream>
#include <streambuf>
#include "cpl_minixml.h"
#include <fstream>
namespace {
const std::string _loggerCat = "TemporalTileProvider";
@@ -56,283 +44,306 @@ namespace {
namespace openspace {
namespace globebrowsing {
const std::string TemporalTileProvider::URL_TIME_PLACEHOLDER("${OpenSpaceTimeId}");
const char* TemporalTileProvider::URL_TIME_PLACEHOLDER("${OpenSpaceTimeId}");
const std::string TemporalTileProvider::TemporalXMLTags::TIME_START = "OpenSpaceTimeStart";
const std::string TemporalTileProvider::TemporalXMLTags::TIME_END = "OpenSpaceTimeEnd";
const std::string TemporalTileProvider::TemporalXMLTags::TIME_RESOLUTION = "OpenSpaceTimeResolution";
const std::string TemporalTileProvider::TemporalXMLTags::TIME_FORMAT = "OpenSpaceTimeIdFormat";
const char* TemporalTileProvider::TemporalXMLTags::TIME_START = "OpenSpaceTimeStart";
const char* TemporalTileProvider::TemporalXMLTags::TIME_END = "OpenSpaceTimeEnd";
const char* TemporalTileProvider::TemporalXMLTags::TIME_RESOLUTION =
"OpenSpaceTimeResolution";
const char* TemporalTileProvider::TemporalXMLTags::TIME_FORMAT = "OpenSpaceTimeIdFormat";
TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
: _initDict(dictionary)
{
TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
: _initDict(dictionary)
{
if (!dictionary.getValue<std::string>(KeyFilePath, _datasetFile)) {
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
}
std::ifstream in(_datasetFile.c_str());
if (!in.is_open()) {
throw ghoul::FileNotFoundError(_datasetFile);
}
// read file
std::string xml((std::istreambuf_iterator<char>(in)), (std::istreambuf_iterator<char>()));
_gdalXmlTemplate = consumeTemporalMetaData(xml);
_defaultTile = getTileProvider()->getDefaultTile();
if (!dictionary.getValue<std::string>(KeyFilePath, _datasetFile)) {
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
}
std::string TemporalTileProvider::consumeTemporalMetaData(const std::string& xml) {
CPLXMLNode* node = CPLParseXMLString(xml.c_str());
std::ifstream in(_datasetFile.c_str());
if (!in.is_open()) {
throw ghoul::FileNotFoundError(_datasetFile);
}
// read file
std::string xml(
std::istreambuf_iterator<char>(in),
(std::istreambuf_iterator<char>())
);
_gdalXmlTemplate = consumeTemporalMetaData(xml);
_defaultTile = getTileProvider()->getDefaultTile();
}
std::string timeStart = getXMLValue(node, TemporalXMLTags::TIME_START, "2000 Jan 1");
std::string timeResolution = getXMLValue(node, TemporalXMLTags::TIME_RESOLUTION, "2d");
std::string timeEnd = getXMLValue(node, TemporalXMLTags::TIME_END, "Now");
std::string timeIdFormat = getXMLValue(node, TemporalXMLTags::TIME_FORMAT, "YYYY-MM-DDThh:mm:ssZ");
std::string TemporalTileProvider::consumeTemporalMetaData(const std::string& xml) {
CPLXMLNode* node = CPLParseXMLString(xml.c_str());
Time start; start.setTime(timeStart);
Time end(Time::now());
if (timeEnd != "Now") {
end.setTime(timeEnd);
}
std::string timeStart = getXMLValue(
node,
TemporalXMLTags::TIME_START,
"2000 Jan 1"
);
std::string timeResolution = getXMLValue(
node,
TemporalXMLTags::TIME_RESOLUTION,
"2d"
);
std::string timeEnd = getXMLValue(
node,
TemporalXMLTags::TIME_END,
"Now"
);
std::string timeIdFormat = getXMLValue(
node,
TemporalXMLTags::TIME_FORMAT,
"YYYY-MM-DDThh:mm:ssZ"
);
Time start; start.setTime(timeStart);
Time end(Time::now());
if (timeEnd != "Now") {
end.setTime(timeEnd);
}
try {
_timeQuantizer = TimeQuantizer(start, end, timeResolution);
}
catch (const ghoul::RuntimeError& e) {
throw ghoul::RuntimeError(
"Could not create time quantizer for Temporal GDAL dataset '" +
_datasetFile + "'. " + e.message);
}
_timeFormat = TimeIdProviderFactory::getProvider(timeIdFormat);
if (!_timeFormat) {
throw ghoul::RuntimeError(
"Invalid Time Format " + timeIdFormat + " in " + _datasetFile
);
}
std::string gdalDescription;
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "GDAL_WMS");
if (gdalNode) {
gdalDescription = CPLSerializeXMLTree(gdalNode);
}
if (!gdalNode) {
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "FilePath");
gdalDescription = std::string(gdalNode->psChild->pszValue);
}
return gdalDescription;
}
std::string TemporalTileProvider::getXMLValue(CPLXMLNode* root, const std::string& key,
const std::string& defaultVal)
{
CPLXMLNode * n = CPLSearchXMLNode(root, key.c_str());
if (!n) {
throw ghoul::RuntimeError(
"Unable to parse file " + _datasetFile + ". " + key + " missing."
);
}
bool hasValue =
(n != nullptr && n->psChild != nullptr && n->psChild->pszValue != nullptr);
return hasValue ? std::string(n->psChild->pszValue) : defaultVal;
}
TileDepthTransform TemporalTileProvider::depthTransform() {
ensureUpdated();
return _currentTileProvider->depthTransform();
}
Tile::Status TemporalTileProvider::getTileStatus(const TileIndex& tileIndex) {
ensureUpdated();
return _currentTileProvider->getTileStatus(tileIndex);
}
Tile TemporalTileProvider::getTile(const TileIndex& tileIndex) {
ensureUpdated();
return _currentTileProvider->getTile(tileIndex);
}
Tile TemporalTileProvider::getDefaultTile() {
return _defaultTile;
}
int TemporalTileProvider::maxLevel() {
ensureUpdated();
return _currentTileProvider->maxLevel();
}
void TemporalTileProvider::ensureUpdated() {
if (_currentTileProvider == nullptr) {
LDEBUG("Warning: update was done lazily");
update();
}
}
void TemporalTileProvider::update() {
auto newCurrent = getTileProvider();
if (newCurrent) {
_currentTileProvider = newCurrent;
}
_currentTileProvider->update();
}
void TemporalTileProvider::reset() {
for (auto& it : _tileProviderMap) {
it.second->reset();
}
//auto end = _tileProviderMap.end();
//for (auto it = _tileProviderMap.begin(); it != end; it++) {
// it->second->reset();
//}
}
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(Time t) {
Time tCopy(t);
if (_timeQuantizer.quantize(tCopy, true)) {
TimeKey timekey = _timeFormat->stringify(tCopy);
try {
_timeQuantizer = TimeQuantizer(start, end, timeResolution);
return getTileProvider(timekey);
}
catch (const ghoul::RuntimeError& e) {
throw ghoul::RuntimeError(
"Could not create time quantizer for Temporal GDAL dataset '" +
_datasetFile + "'. " + e.message);
}
_timeFormat = TimeIdProviderFactory::getProvider(timeIdFormat);
if (!_timeFormat) {
throw ghoul::RuntimeError("Invalid Time Format " + timeIdFormat + " in " + _datasetFile);
}
std::string gdalDescription;
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "GDAL_WMS");
if (gdalNode) {
gdalDescription = CPLSerializeXMLTree(gdalNode);
}
if (!gdalNode) {
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "FilePath");
gdalDescription = std::string(gdalNode->psChild->pszValue);
}
return gdalDescription;
}
std::string TemporalTileProvider::getXMLValue(CPLXMLNode* root, const std::string& key, const std::string& defaultVal) {
CPLXMLNode * n = CPLSearchXMLNode(root, key.c_str());
if (!n) {
throw ghoul::RuntimeError("Unable to parse file " + _datasetFile + ". " + key + " missing.");
}
bool hasValue = (n != nullptr && n->psChild != nullptr && n->psChild->pszValue != nullptr);
return hasValue ? std::string(n->psChild->pszValue) : defaultVal;
}
TileDepthTransform TemporalTileProvider::depthTransform() {
ensureUpdated();
return _currentTileProvider->depthTransform();
}
Tile::Status TemporalTileProvider::getTileStatus(const TileIndex& tileIndex) {
ensureUpdated();
return _currentTileProvider->getTileStatus(tileIndex);
}
Tile TemporalTileProvider::getTile(const TileIndex& tileIndex) {
ensureUpdated();
return _currentTileProvider->getTile(tileIndex);
}
Tile TemporalTileProvider::getDefaultTile() {
return _defaultTile;
}
int TemporalTileProvider::maxLevel() {
ensureUpdated();
return _currentTileProvider->maxLevel();
}
void TemporalTileProvider::ensureUpdated() {
if (_currentTileProvider == nullptr) {
LDEBUG("Warning: update was done lazily");
update();
LERROR(e.message);
return nullptr;
}
}
return nullptr;
}
void TemporalTileProvider::update() {
auto newCurrent = getTileProvider();
if (newCurrent) {
_currentTileProvider = newCurrent;
}
_currentTileProvider->update();
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(TimeKey timekey) {
auto it = _tileProviderMap.find(timekey);
if (it != _tileProviderMap.end()) {
return it->second;
}
else {
auto tileProvider = initTileProvider(timekey);
void TemporalTileProvider::reset() {
auto end = _tileProviderMap.end();
for (auto it = _tileProviderMap.begin(); it != end; it++) {
it->second->reset();
}
}
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(Time t) {
Time tCopy(t);
if (_timeQuantizer.quantize(tCopy, true)) {
TimeKey timekey = _timeFormat->stringify(tCopy);
try {
return getTileProvider(timekey);
}
catch (const ghoul::RuntimeError& e) {
LERROR(e.message);
return nullptr;
}
}
return nullptr;
}
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(TimeKey timekey) {
auto it = _tileProviderMap.find(timekey);
if (it != _tileProviderMap.end()) {
return it->second;
}
else {
auto tileProvider = initTileProvider(timekey);
_tileProviderMap[timekey] = tileProvider;
return tileProvider;
}
}
std::shared_ptr<TileProvider> TemporalTileProvider::initTileProvider(TimeKey timekey) {
std::string gdalDatasetXml = getGdalDatasetXML(timekey);
_initDict.setValue<std::string>(KeyFilePath, gdalDatasetXml);
auto tileProvider = std::make_shared<CachingTileProvider>(_initDict);
_tileProviderMap[timekey] = tileProvider;
return tileProvider;
}
}
std::shared_ptr<TileProvider> TemporalTileProvider::initTileProvider(TimeKey timekey) {
std::string gdalDatasetXml = getGdalDatasetXML(timekey);
_initDict.setValue<std::string>(KeyFilePath, gdalDatasetXml);
auto tileProvider = std::make_shared<CachingTileProvider>(_initDict);
return tileProvider;
}
std::string TemporalTileProvider::getGdalDatasetXML(Time t) {
TimeKey timekey = _timeFormat->stringify(t);
return getGdalDatasetXML(timekey);
}
std::string TemporalTileProvider::getGdalDatasetXML(Time t) {
TimeKey timekey = _timeFormat->stringify(t);
return getGdalDatasetXML(timekey);
}
std::string TemporalTileProvider::getGdalDatasetXML(TimeKey timeKey) {
std::string xmlTemplate(_gdalXmlTemplate);
size_t pos = xmlTemplate.find(URL_TIME_PLACEHOLDER);
size_t numChars = URL_TIME_PLACEHOLDER.length();
ghoul_assert(pos != std::string::npos, "Invalid dataset file");
std::string timeSpecifiedXml = xmlTemplate.replace(pos, numChars, timeKey);
return timeSpecifiedXml;
}
std::string TemporalTileProvider::getGdalDatasetXML(TimeKey timeKey) {
std::string xmlTemplate(_gdalXmlTemplate);
size_t pos = xmlTemplate.find(URL_TIME_PLACEHOLDER);
//size_t numChars = std::string(URL_TIME_PLACEHOLDER).length();
size_t numChars = strlen(URL_TIME_PLACEHOLDER);
ghoul_assert(pos != std::string::npos, "Invalid dataset file");
std::string timeSpecifiedXml = xmlTemplate.replace(pos, numChars, timeKey);
return timeSpecifiedXml;
}
//////////////////////////////////////////////////////////////////////////////////////
// Time Id Providers //
//////////////////////////////////////////////////////////////////////////////////////
std::string YYYY_MM_DD::stringify(const Time& t) const {
return t.ISO8601().substr(0, 10);
}
std::string YYYY_MM_DD::stringify(const Time& t) const {
return t.ISO8601().substr(0, 10);
}
std::string YYYY_MM_DDThhColonmmColonssZ::stringify(const Time& t) const {
return t.ISO8601().substr(0, 19) + "Z";
}
std::string YYYY_MM_DDThhColonmmColonssZ::stringify(const Time& t) const {
return t.ISO8601().substr(0, 19) + "Z";
}
std::string YYYY_MM_DDThh_mm_ssZ::stringify(const Time& t) const {
std::string timeString = t.ISO8601().substr(0, 19) + "Z";
replace( timeString.begin(), timeString.end(), ':', '_' );
return timeString;
std::string YYYY_MM_DDThh_mm_ssZ::stringify(const Time& t) const {
std::string timeString = t.ISO8601().substr(0, 19) + "Z";
replace( timeString.begin(), timeString.end(), ':', '_' );
return timeString;
}
bool TimeIdProviderFactory::initialized = false;
std::unordered_map<std::string, std::unique_ptr<TimeFormat>>
TimeIdProviderFactory::_timeIdProviderMap =
std::unordered_map<std::string, std::unique_ptr<TimeFormat>>();
void TimeIdProviderFactory::init() {
_timeIdProviderMap.insert({ "YYYY-MM-DD" , std::make_unique<YYYY_MM_DD>() });
_timeIdProviderMap.insert(
{ "YYYY-MM-DDThh:mm:ssZ", std::make_unique<YYYY_MM_DDThhColonmmColonssZ>() }
);
initialized = true;
_timeIdProviderMap.insert(
{ "YYYY-MM-DDThh_mm_ssZ", std::make_unique<YYYY_MM_DDThh_mm_ssZ>() }
);
initialized = true;
}
TimeFormat* TimeIdProviderFactory::getProvider(const std::string& format) {
if (!initialized) {
init();
}
ghoul_assert(
_timeIdProviderMap.find(format) != _timeIdProviderMap.end(),
"Unsupported Time format: " << format
);
return _timeIdProviderMap[format].get();
}
//////////////////////////////////////////////////////////////////////////////////////
// Time Id Providers Facotry //
//////////////////////////////////////////////////////////////////////////////////////
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end, double resolution)
: _timerange(start.j2000Seconds(), end.j2000Seconds())
, _resolution(resolution)
{}
bool TimeIdProviderFactory::initialized = false;
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end,
const std::string& resolution)
: TimeQuantizer(start, end, parseTimeResolutionStr(resolution))
{}
std::unordered_map<std::string, std::unique_ptr<TimeFormat>> TimeIdProviderFactory::_timeIdProviderMap = std::unordered_map<std::string, std::unique_ptr<TimeFormat>>();
void TimeIdProviderFactory::init() {
_timeIdProviderMap.insert(
std::pair<std::string, std::unique_ptr<TimeFormat> >( "YYYY-MM-DD", std::make_unique<YYYY_MM_DD>() ));
_timeIdProviderMap.insert(std::pair<std::string, std::unique_ptr<TimeFormat> > ( "YYYY-MM-DDThh:mm:ssZ", std::make_unique<YYYY_MM_DDThhColonmmColonssZ>() ));
initialized = true;
_timeIdProviderMap.insert(std::pair<std::string, std::unique_ptr<TimeFormat> > ( "YYYY-MM-DDThh_mm_ssZ", std::make_unique<YYYY_MM_DDThh_mm_ssZ>() ));
initialized = true;
}
TimeFormat* TimeIdProviderFactory::getProvider(const std::string& format) {
if (!initialized) {
init();
}
ghoul_assert(_timeIdProviderMap.find(format) != _timeIdProviderMap.end(),
"Unsupported Time format: " << format);
return _timeIdProviderMap[format].get();
}
//////////////////////////////////////////////////////////////////////////////////////
// Time Quantizer //
//////////////////////////////////////////////////////////////////////////////////////
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end, double resolution)
: _timerange(start.j2000Seconds(), end.j2000Seconds())
, _resolution(resolution)
{
}
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end, const std::string& resolution)
: TimeQuantizer(start, end, parseTimeResolutionStr(resolution))
{
}
double TimeQuantizer::parseTimeResolutionStr(const std::string& resoltutionStr) {
const char unit = resoltutionStr.back();
std::string numberString = resoltutionStr.substr(0, resoltutionStr.length() - 1);
double TimeQuantizer::parseTimeResolutionStr(const std::string& resoltutionStr) {
const char unit = resoltutionStr.back();
std::string numberString = resoltutionStr.substr(0, resoltutionStr.length() - 1);
char* p;
double value = strtol(numberString.c_str(), &p, 10);
if (*p) { // not a number
throw ghoul::RuntimeError("Cannot convert " + numberString + " to number");
}
else {
// convert value to seconds, based on unit.
// The switch statment has intentional fall throughs
switch (unit) {
case 'y': value *= 365;
case 'd': value *= 24.0;
case 'h': value *= 60.0;
case 'm': value *= 60.0;
case 's': value *= 1.0;
break;
default:
throw ghoul::RuntimeError("Invalid unit format '" + std::string(1, unit) +
"'. Expected 'y', 'd', 'h', 'm' or 's'.");
}
return value;
}
char* p;
double value = strtol(numberString.c_str(), &p, 10);
if (*p) { // not a number
throw ghoul::RuntimeError("Cannot convert " + numberString + " to number");
}
else {
// convert value to seconds, based on unit.
// The switch statment has intentional fall throughs
switch (unit) {
case 'y': value *= 365;
case 'd': value *= 24.0;
case 'h': value *= 60.0;
case 'm': value *= 60.0;
case 's': value *= 1.0;
break;
default:
throw ghoul::RuntimeError("Invalid unit format '" + std::string(1, unit) +
"'. Expected 'y', 'd', 'h', 'm' or 's'.");
}
return value;
}
}
bool TimeQuantizer::quantize(Time& t, bool clamp) const {
double unquantized = t.j2000Seconds();
if (_timerange.includes(unquantized)) {
double quantized = std::floor((unquantized - _timerange.start) / _resolution) * _resolution + _timerange.start;
t.setTime(quantized);
return true;
}
else if (clamp) {
double clampedTime = unquantized;
clampedTime = std::max(clampedTime, _timerange.start);
clampedTime = std::min(clampedTime, _timerange.end);
t.setTime(clampedTime);
return true;
}
else {
return false;
}
bool TimeQuantizer::quantize(Time& t, bool clamp) const {
double unquantized = t.j2000Seconds();
if (_timerange.includes(unquantized)) {
double quantized = std::floor((unquantized - _timerange.start) / _resolution) * _resolution + _timerange.start;
t.setTime(quantized);
return true;
}
else if (clamp) {
double clampedTime = unquantized;
clampedTime = std::max(clampedTime, _timerange.start);
clampedTime = std::min(clampedTime, _timerange.end);
t.setTime(clampedTime);
return true;
}
else {
return false;
}
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,323 +1,299 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TEMPORAL_TILE_PROVIDER_H__
#define __TEMPORAL_TILE_PROVIDER_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TEMPORAL_TILE_PROVIDER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TEMPORAL_TILE_PROVIDER_H__
#include <ghoul/opengl/texture.h>
#include <ghoul/misc/dictionary.h>
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <openspace/util/time.h>
#include <openspace/util/timerange.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <gdal_priv.h>
//////////////////////////////////////////////////////////////////////////////////////////
// TILE PROVIDER //
//////////////////////////////////////////////////////////////////////////////////////////
struct CPLXMLNode;
namespace openspace {
namespace globebrowsing {
//////////////////////////////////////////////////////////////////////////////////////
// Time Id Providers //
//////////////////////////////////////////////////////////////////////////////////////
/**
* Interface for stringifying OpenSpace Time instances.
*
* Once OpenSpace has a proper Time format class, this should be handled by that instead
* of here.
*/
struct TimeFormat {
/**
* Interface for stringifying OpenSpace Time instances.
*
* Once OpenSpace has a proper Time format class, this should be
* handled by that instead of here.
*/
struct TimeFormat {
/**
* Stringifies a OpenSpace time instance
* \param t The time to be stringifyed
* \returns A string description of the provided time
*/
virtual std::string stringify(const Time& t) const = 0;
};
/**
* Stringifies OpenSpace to the format "YYYY-MM-DD".
* Example: 2016-09-08
*/
struct YYYY_MM_DD : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
/**
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
* Example: 2016-09-08T23:05:05Z
*/
struct YYYY_MM_DDThhColonmmColonssZ : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
/**
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
* Example: 2016-09-08T23:05:05Z
* Stringifies a OpenSpace time instance
* \param t The time to be stringifyed
* \returns A string description of the provided time
*/
struct YYYY_MM_DDThh_mm_ssZ : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
virtual std::string stringify(const Time& t) const = 0;
};
/**
* Stringifies OpenSpace to the format "YYYY-MM-DD".
* Example: 2016-09-08
*/
struct YYYY_MM_DD : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
/**
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
* Example: 2016-09-08T23:05:05Z
*/
struct YYYY_MM_DDThhColonmmColonssZ : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
/**
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
* Example: 2016-09-08T23:05:05Z
*/
struct YYYY_MM_DDThh_mm_ssZ : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
/**
* Static factory class for providing different TimeFormats.
* A time format stringifier is retrieved by a name of the format.
* See implementation of <code>init()</code> to see what time
* id formats are supported.
*/
struct TimeIdProviderFactory {
/**
* Maps a name of a format to an implementation of a TimeFormat.
* Calling this method will also initialize the TimeIdProviderFactory
* if it hasn't been.
*
* See implementation of <code>init()</code> for supported time formats.
*
* \param format - name of TimeFormat, eg "YYYY-MM-DDThh:mm:ssZ".
* \returns a concrete TimeFormat used to stringify instances of Time
*/
static TimeFormat* getProvider(const std::string& format);
/**
* Static factory class for providing different TimeFormats.
* A time format stringifier is retrieved by a name of the format.
* See implementation of <code>init()</code> to see what time
* id formats are supported.
*/
struct TimeIdProviderFactory {
/**
* Maps a name of a format to an implementation of a TimeFormat.
* Calling this method will also initialize the TimeIdProviderFactory
* if it hasn't been.
*
* See implementation of <code>init()</code> for supported time formats.
*
* \param format - name of TimeFormat, eg "YYYY-MM-DDThh:mm:ssZ".
* \returns a concrete TimeFormat used to stringify instances of Time
*/
static TimeFormat* getProvider(const std::string& format);
* Registers all supported TimeFormats.
*/
static void init();
/**
* Registers all supported TimeFormats.
*/
static void init();
static std::unordered_map<std::string, std::unique_ptr<TimeFormat>> _timeIdProviderMap;
static bool initialized;
};
static std::unordered_map<std::string, std::unique_ptr<TimeFormat>> _timeIdProviderMap;
static bool initialized;
};
//////////////////////////////////////////////////////////////////////////////////////
// Time Quantizer //
//////////////////////////////////////////////////////////////////////////////////////
/**
* Used to quantize time to descrete values.
*/
struct TimeQuantizer {
TimeQuantizer() {}
TimeQuantizer(const Time& start, const Time& end, double resolution);
TimeQuantizer(const Time& start, const Time& end, const std::string& resolutionStr);
/**
* Used to quantize time to descrete values.
*/
struct TimeQuantizer {
TimeQuantizer() {}
TimeQuantizer(const Time& start, const Time& end, double resolution);
TimeQuantizer(const Time& start, const Time& end, const std::string& resolutionStr);
/**
* Takes a time resulition string and parses it into a double
* value representing the time resolution as seconds.
*
* Example: parseTimeResolutionStr("1d");
*
* \param resoltutionStr with the format {number}{unit}
* where supported units are:
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears
*
* \returns the time resolution in seconds
*/
static double parseTimeResolutionStr(const std::string& resoltutionStr);
/**
* Quantizes a OpenSpace Time into descrete values.
* If the provided Time t is outside the time range, it will
* be clamped to the the time range.
*
* \param t Time instance, which will be quantized
* \param clamp Whether or not time should be clamped if not t is in the time range
* \returns wether or not time was quantized
*/
bool quantize(Time& t, bool clamp) const;
private:
TimeRange _timerange;
double _resolution;
};
//////////////////////////////////////////////////////////////////////////////////////
// Temporal tile Provider //
//////////////////////////////////////////////////////////////////////////////////////
* Takes a time resulition string and parses it into a double
* value representing the time resolution as seconds.
*
* Example: parseTimeResolutionStr("1d");
*
* \param resoltutionStr with the format {number}{unit}
* where supported units are:
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears
*
* \returns the time resolution in seconds
*/
static double parseTimeResolutionStr(const std::string& resoltutionStr);
/**
* Provide <code>Tile</code>s from web map services that have temporal resolution.
*
* TemporalTileProviders are instantiated using a ghoul::Dictionary,
* and must define a filepath to a Openspace Temporal dataset description file.
* This is an xml-file that defines the same meta data as the GDAL wms description
* (http://www.gdal.org/frmt_wms.html), but augmented with some
* extra tags describing the temporal properties of the dataset. See
* <code>TemporalTileProvider::TemporalXMLTags</code>
*
*/
class TemporalTileProvider : public TileProvider {
public:
* Quantizes a OpenSpace Time into descrete values.
* If the provided Time t is outside the time range, it will
* be clamped to the the time range.
*
* \param t Time instance, which will be quantized
* \param clamp Whether or not time should be clamped if not t is in the time range
* \returns wether or not time was quantized
*/
bool quantize(Time& t, bool clamp) const;
private:
TimeRange _timerange;
double _resolution;
};
/**
* Provide <code>Tile</code>s from web map services that have temporal resolution.
*
* TemporalTileProviders are instantiated using a ghoul::Dictionary,
* and must define a filepath to a Openspace Temporal dataset description file.
* This is an xml-file that defines the same meta data as the GDAL wms description
* (http://www.gdal.org/frmt_wms.html), but augmented with some
* extra tags describing the temporal properties of the dataset. See
* <code>TemporalTileProvider::TemporalXMLTags</code>
*
*/
class TemporalTileProvider : public TileProvider {
public:
/**
* Dictionary constructor. Must provide KeyFilePath as defined in .cpp file.
*/
TemporalTileProvider(const ghoul::Dictionary& dictionary);
// These methods implements the TileProvider interface
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
typedef std::string TimeKey;
std::shared_ptr<TileProvider> getTileProvider(Time t = Time::ref());
std::shared_ptr<TileProvider> getTileProvider(TimeKey timekey);
private:
/**
* A placeholder string that must be provided in the WMS template url. This
* placeholder will be replaced by quantized date-time strings during run time
* in order to access the datasets for different instances of time.
*/
static const char* URL_TIME_PLACEHOLDER;
/**
* These are tags that TemporalTileProviders must be able to read from the XML
* file provided in the ghoul::Dictionary used to create this provider. These
* tags describe the temporal properties of the dataset.
*/
static const struct TemporalXMLTags {
/**
* Dictionary constructor. Must provide KeyFilePath as defined in .cpp file.
*/
TemporalTileProvider(const ghoul::Dictionary& dictionary);
// These methods implements the TileProvider interface
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
typedef std::string TimeKey;
std::shared_ptr<TileProvider> getTileProvider(Time t = Time::ref());
std::shared_ptr<TileProvider> getTileProvider(TimeKey timekey);
private:
* Tag should contain a ISO8601 time specifying the datasets start time
*/
static const char* TIME_START;
/**
* A placeholder string that must be provided in the WMS template url. This
* placeholder will be replaced by quantized date-time strings during run time
* in order to access the datasets for different instances of time.
*/
static const std::string URL_TIME_PLACEHOLDER;
* Tag should contain a ISO8601 time specifying the datasets end time
* Example 1: "2016 SEP 08".
* Example 2: "now" - sets the dataset's end time to the current time.
*/
static const char* TIME_END;
/**
* These are tags that TemporalTileProviders must be able to read from the XML
* file provided in the ghoul::Dictionary used to create this provider. These
* tags describe the temporal properties of the dataset.
*/
static const struct TemporalXMLTags {
/**
* Tag should contain a ISO8601 time specifying the datasets start time
*/
static const std::string TIME_START;
* Tag should contain the time resolution of the dataset.
* The resolution is defined by a number along with a unit specifying how
* often the dataset is updated temporally. Supported units are:
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears.
*
* Example 1: "2d" - dataset updated every other day.
* Example 2: "1h" - dataset is updated every hour.
*/
static const char* TIME_RESOLUTION;
/**
* Tag should contain a ISO8601 time specifying the datasets end time
* Example 1: "2016 SEP 08".
* Example 2: "now" - sets the dataset's end time to the current time.
*/
static const std::string TIME_END;
/**
* Tag should contain the time resolution of the dataset.
* The resolution is defined by a number along with a unit specifying how
* often the dataset is updated temporally. Supported units are:
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears.
*
* Example 1: "2d" - dataset updated every other day.
* Example 2: "1h" - dataset is updated every hour.
*/
static const std::string TIME_RESOLUTION;
/**
* Tag should contain a string specifying the date-time format expected by the
* WMS.
*/
static const std::string TIME_FORMAT;
};
/**
* Tag should contain a string specifying the date-time format expected by the
* WMS.
*/
static const char* TIME_FORMAT;
};
/**
* Create a GDAL dataset description based on the time t
* \param t Time to generate a GDAL dataset description for
* \returns a GDAL dataset description
*/
std::string getGdalDatasetXML(Time t);
/**
* Create a GDAL dataset description based on the time t
* \param t Time to generate a GDAL dataset description for
* \returns a GDAL dataset description
*/
std::string getGdalDatasetXML(Time t);
/**
* Create a GDAL dataset description associated with the provided TimeKey
* \param key The TimeKey specifying time
* \returns a GDAL dataset description
*/
std::string getGdalDatasetXML(TimeKey key);
/**
* Create a GDAL dataset description associated with the provided TimeKey
* \param key The TimeKey specifying time
* \returns a GDAL dataset description
*/
std::string getGdalDatasetXML(TimeKey key);
/**
* Instantiates a new TileProvder for the temporal dataset at the time
* specified.
*
* This method replaced the <code>URL_TIME_PLACEHOLDER</code> in the template URL
* with the provided timekey, the opens a new GDAL dataset with that URL.
*
* \param timekey time specifying dataset's temporality
* \returns newly instantiated TileProvider
*/
std::shared_ptr<TileProvider> initTileProvider(TimeKey timekey);
/**
* Instantiates a new TileProvder for the temporal dataset at the time
* specified.
*
* This method replaced the <code>URL_TIME_PLACEHOLDER</code> in the template URL
* with the provided timekey, the opens a new GDAL dataset with that URL.
*
* \param timekey time specifying dataset's temporality
* \returns newly instantiated TileProvider
*/
std::shared_ptr<TileProvider> initTileProvider(TimeKey timekey);
/**
* Takes as input a Openspace Temporal dataset description, extracts the temporal
* metadata provided by reading the <code>TemporalXMLTags</code>, removes the
* read tags from the description, and returns a GDAL template GDAL dataset
* description. The template GDAL dataset description has the a
* <code>URL_TIME_PLACEHOLDER</code> still in it, which needs to be replaced before
* GDAL can open it as a GDALDataset.
*
* \param xml Openspace Temporal dataset description
* \returns a GDAL template data description.
*/
std::string consumeTemporalMetaData(const std::string &xml);
/**
* Takes as input a Openspace Temporal dataset description, extracts the temporal
* metadata provided by reading the <code>TemporalXMLTags</code>, removes the
* read tags from the description, and returns a GDAL template GDAL dataset
* description. The template GDAL dataset description has the a
* <code>URL_TIME_PLACEHOLDER</code> still in it, which needs to be replaced before
* GDAL can open it as a GDALDataset.
*
* \param xml Openspace Temporal dataset description
* \returns a GDAL template data description.
*/
std::string consumeTemporalMetaData(const std::string &xml);
/**
* Helper method to read a XML value from a XML tree.
* \param node XML tree to search in
* \param key XML tag to find the value for
* \param defaultVal value to return if key was not found
* \returns the value of the Key, or defaultVal if key was undefined.
*/
std::string getXMLValue(CPLXMLNode* node, const std::string& key, const std::string& defaultVal);
/**
* Helper method to read a XML value from a XML tree.
* \param node XML tree to search in
* \param key XML tag to find the value for
* \param defaultVal value to return if key was not found
* \returns the value of the Key, or defaultVal if key was undefined.
*/
std::string getXMLValue(CPLXMLNode* node, const std::string& key, const std::string& defaultVal);
/**
* Ensures that the TemporalTileProvider is up to date.
*/
void ensureUpdated();
/**
* Ensures that the TemporalTileProvider is up to date.
*/
void ensureUpdated();
//////////////////////////////////////////////////////////////////////////////////
// Members variables //
//////////////////////////////////////////////////////////////////////////////////
std::string _datasetFile;
std::string _gdalXmlTemplate;
std::string _datasetFile;
std::string _gdalXmlTemplate;
std::unordered_map<TimeKey, std::shared_ptr<TileProvider> > _tileProviderMap;
std::unordered_map<TimeKey, std::shared_ptr<TileProvider> > _tileProviderMap;
// Used for creation of time specific instances of CachingTileProvider
ghoul::Dictionary _initDict;
// Used for creation of time specific instances of CachingTileProvider
ghoul::Dictionary _initDict;
Tile _defaultTile;
std::shared_ptr<TileProvider> _currentTileProvider;
Tile _defaultTile;
std::shared_ptr<TileProvider> _currentTileProvider;
TimeFormat * _timeFormat;
TimeQuantizer _timeQuantizer;
};
TimeFormat* _timeFormat;
TimeQuantizer _timeQuantizer;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TEMPORAL_TILE_PROVIDER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TEMPORAL_TILE_PROVIDER_H__

View File

@@ -1,268 +1,261 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tileprovider/texttileprovider.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/font/fontmanager.h>
#include <openspace/engine/openspaceengine.h>
#include <sstream>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/misc/dictionary.h>
namespace {
const std::string _loggerCat = "TextTileProvider";
}
using namespace ghoul::fontrendering;
namespace openspace {
namespace globebrowsing {
TextTileProvider::TextTileProvider(const glm::uvec2& textureSize, size_t fontSize)
: _tileCache(500)
, _textureSize(textureSize)
, _fontSize(fontSize)
{
_font = OsEng.fontManager().font("Mono", _fontSize);
TextTileProvider::TextTileProvider(const glm::uvec2& textureSize, size_t fontSize)
: _tileCache(500)
, _textureSize(textureSize)
, _fontSize(fontSize)
{
_font = OsEng.fontManager().font("Mono", _fontSize);
_fontRenderer = std::unique_ptr<FontRenderer>(FontRenderer::createDefault());
_fontRenderer->setFramebufferSize(textureSize);
_fontRenderer = std::unique_ptr<FontRenderer>(FontRenderer::createDefault());
_fontRenderer->setFramebufferSize(textureSize);
glGenFramebuffers(1, &_fbo);
}
glGenFramebuffers(1, &_fbo);
}
TextTileProvider::~TextTileProvider() {
glDeleteFramebuffers(1, &_fbo);
}
TextTileProvider::~TextTileProvider() {
glDeleteFramebuffers(1, &_fbo);
}
Tile TextTileProvider::getTile(const TileIndex& tileIndex) {
TileHashKey key = tileIndex.hashKey();
Tile TextTileProvider::getTile(const TileIndex& tileIndex) {
TileHashKey key = tileIndex.hashKey();
if (!_tileCache.exist(key)) {
_tileCache.put(key, createChunkIndexTile(tileIndex));
}
return _tileCache.get(key);
if (!_tileCache.exist(key)) {
_tileCache.put(key, createChunkIndexTile(tileIndex));
}
Tile TextTileProvider::getDefaultTile() {
return Tile::TileUnavailable;
}
return _tileCache.get(key);
}
Tile TextTileProvider::getDefaultTile() {
return Tile::TileUnavailable;
}
Tile::Status TextTileProvider::getTileStatus(const TileIndex& index) {
return Tile::Status::OK;
}
Tile::Status TextTileProvider::getTileStatus(const TileIndex& index) {
return Tile::Status::OK;
}
TileDepthTransform TextTileProvider::depthTransform() {
TileDepthTransform transform;
transform.depthOffset = 0.0f;
transform.depthScale = 1.0f;
return transform;
}
TileDepthTransform TextTileProvider::depthTransform() {
TileDepthTransform transform;
transform.depthOffset = 0.0f;
transform.depthScale = 1.0f;
return transform;
}
void TextTileProvider::update() {
// nothing to be done
}
void TextTileProvider::update() {}
void TextTileProvider::reset() {
_tileCache.clear();
}
void TextTileProvider::reset() {
_tileCache.clear();
}
Tile TextTileProvider::createChunkIndexTile(const TileIndex& tileIndex) {
Tile tile = backgroundTile(tileIndex);
Tile TextTileProvider::createChunkIndexTile(const TileIndex& tileIndex) {
Tile tile = backgroundTile(tileIndex);
// Keep track of defaultFBO and viewport to be able to reset state when done
GLint defaultFBO;
GLint viewport[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
glGetIntegerv(GL_VIEWPORT, viewport);
// Keep track of defaultFBO and viewport to be able to reset state when done
GLint defaultFBO;
GLint viewport[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
glGetIntegerv(GL_VIEWPORT, viewport);
// Render to texture
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
*(tile.texture),
0
);
// Render to texture
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
*(tile.texture),
0
);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
//LDEBUG(status);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glViewport(
0, 0,
static_cast<GLsizei>(tile.texture->width()),
static_cast<GLsizei>(tile.texture->height())
);
glViewport(
0, 0,
static_cast<GLsizei>(tile.texture->width()),
static_cast<GLsizei>(tile.texture->height())
);
ghoul_assert(_fontRenderer != nullptr, "_fontRenderer must not be null");
renderText(*_fontRenderer, tileIndex);
ghoul_assert(_fontRenderer != nullptr, "_fontRenderer must not be null");
renderText(*_fontRenderer, tileIndex);
// Reset state: bind default FBO and set viewport to what it was
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
// Reset state: bind default FBO and set viewport to what it was
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
return tile;
}
int TextTileProvider::maxLevel() {
return 1337; // unlimited
}
TileHashKey TextTileProvider::toHash(const TileIndex& tileIndex) const {
return tileIndex.hashKey();
}
Tile TextTileProvider::backgroundTile(const TileIndex& tileIndex) const {
glm::uvec4 color = { 0, 0, 0, 0 };
return Tile::createPlainTile(_textureSize, color);
}
void TileIndexTileProvider::renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const {
fontRenderer.render(
*_font,
glm::vec2(
_textureSize.x / 4 - (_textureSize.x / 32) * log10(1 << tileIndex.level),
_textureSize.y / 2 + _fontSize),
glm::vec4(1.0, 0.0, 0.0, 1.0),
"level: %i \nx: %i \ny: %i",
tileIndex.level, tileIndex.x, tileIndex.y
);
}
namespace {
const char* KeyRadii = "Radii";
const char* KeyBackgroundImagePath = "BackgroundImagePath";
}
SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary)
{
_fontSize = 50;
FontManager& fm = OsEng.fontManager();
_font = fm.font("Mono", _fontSize);
glm::dvec3 radii(1,1,1);
if (!dictionary.getValue(KeyRadii, radii)) {
throw std::runtime_error("Must define key '" + std::string(KeyRadii) + "'");
}
_ellipsoid = Ellipsoid(radii);
_backgroundTile.status = Tile::Status::Unavailable;
std::string backgroundImagePath;
if (dictionary.getValue(KeyBackgroundImagePath, backgroundImagePath)) {
using namespace ghoul::io;
std::string imgAbsPath = absPath(backgroundImagePath);
_backgroundTile.texture = TextureReader::ref().loadTexture(imgAbsPath);
_backgroundTile.texture->uploadTexture();
_backgroundTile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
_backgroundTile.status = Tile::Status::OK;
}
}
void SizeReferenceTileProvider::renderText(const FontRenderer& fontRenderer,
const TileIndex& tileIndex) const
{
GeodeticPatch patch(tileIndex);
bool aboveEquator = patch.isNorthern();
double tileLongitudalLength = roundedLongitudalLength(tileIndex);
std::string unit = "m";
if (tileLongitudalLength > 9999) {
tileLongitudalLength *= 0.001;
unit = "km";
}
glm::vec2 textPosition;
textPosition.x = 0;
textPosition.y = aboveEquator ? _fontSize / 2 : _textureSize.y - 3 * _fontSize / 2;
glm::vec4 color(1.0, 1.0, 1.0, 1.0);
fontRenderer.render(
*_font,
textPosition,
color,
" %.0f %s",
tileLongitudalLength, unit.c_str()
);
}
int SizeReferenceTileProvider::roundedLongitudalLength(const TileIndex& tileIndex) const {
GeodeticPatch patch(tileIndex);
bool aboveEquator = patch.isNorthern();
double lat = aboveEquator ? patch.minLat() : patch.maxLat();
double lon1 = patch.minLon();
double lon2 = patch.maxLon();
int l = static_cast<int>(_ellipsoid.longitudalDistance(lat, lon1, lon2));
bool useKm = l > 9999;
if (useKm) {
l /= 1000;
}
l = std::round(l);
if (useKm) {
l *= 1000;
}
return l;
}
TileHashKey SizeReferenceTileProvider::toHash(const TileIndex& tileIndex) const {
int l = roundedLongitudalLength(tileIndex);
TileHashKey key = static_cast<TileHashKey>(l);
return key;
}
Tile SizeReferenceTileProvider::backgroundTile(const TileIndex& tileIndex) const {
if (_backgroundTile.status == Tile::Status::OK) {
Tile tile;
auto t = _backgroundTile.texture;
void* pixelData = new char[t->expectedPixelDataSize()];
memcpy(pixelData, t->pixelData(), t->expectedPixelDataSize());
tile.texture = std::make_shared<Texture>(
pixelData,
t->dimensions(),
t->format(),
t->internalFormat(),
t->dataType(),
t->filter(),
t->wrapping()
);
tile.texture->uploadTexture();
tile.texture->setDataOwnership(Texture::TakeOwnership::Yes);
tile.status = Tile::Status::OK;
return tile;
}
int TextTileProvider::maxLevel() {
return 1337; // unlimited
}
TileHashKey TextTileProvider::toHash(const TileIndex& tileIndex) const {
return tileIndex.hashKey();
}
Tile TextTileProvider::backgroundTile(const TileIndex& tileIndex) const {
glm::uvec4 color = { 0, 0, 0, 0 };
return Tile::createPlainTile(_textureSize, color);
}
//////////////////////////////////////////////////////////////////////////////////////
// Chunk Index Tile Provider //
//////////////////////////////////////////////////////////////////////////////////////
void TileIndexTileProvider::renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const {
fontRenderer.render(
*_font,
glm::vec2(
_textureSize.x / 4 - (_textureSize.x / 32) * log10(1 << tileIndex.level),
_textureSize.y / 2 + _fontSize),
glm::vec4(1.0, 0.0, 0.0, 1.0),
"level: %i \nx: %i \ny: %i",
tileIndex.level, tileIndex.x, tileIndex.y
);
}
//////////////////////////////////////////////////////////////////////////////////////
// Tile Size Reference Tile Provider //
//////////////////////////////////////////////////////////////////////////////////////
namespace {
const std::string KeyRadii = "Radii";
const std::string KeyBackgroundImagePath = "BackgroundImagePath";
}
SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) {
_fontSize = 50;
ghoul::fontrendering::FontManager& fm = OsEng.fontManager();
_font = fm.font("Mono", _fontSize);
glm::dvec3 radii(1,1,1);
if (!dictionary.getValue(KeyRadii, radii)) {
throw std::runtime_error("Must define key '" + KeyRadii + "'");
}
_ellipsoid = Ellipsoid(radii);
_backgroundTile.status = Tile::Status::Unavailable;
std::string backgroundImagePath;
if (dictionary.getValue(KeyBackgroundImagePath, backgroundImagePath)) {
using namespace ghoul::io;
std::string imgAbsPath = absPath(backgroundImagePath);
_backgroundTile.texture = TextureReader::ref().loadTexture(imgAbsPath);
_backgroundTile.texture->uploadTexture();
_backgroundTile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
_backgroundTile.status = Tile::Status::OK;
}
}
void SizeReferenceTileProvider::renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const {
GeodeticPatch patch(tileIndex);
bool aboveEquator = patch.isNorthern();
double tileLongitudalLength = roundedLongitudalLength(tileIndex);
std::string unit = "m";
if (tileLongitudalLength > 9999) {
tileLongitudalLength *= 0.001;
unit = "km";
}
glm::vec2 textPosition;
textPosition.x = 0;
textPosition.y = aboveEquator ? _fontSize / 2 : _textureSize.y - 3 * _fontSize / 2;
glm::vec4 color(1.0, 1.0, 1.0, 1.0);
fontRenderer.render(
*_font,
textPosition,
color,
" %.0f %s",
tileLongitudalLength, unit.c_str()
);
}
int SizeReferenceTileProvider::roundedLongitudalLength(const TileIndex& tileIndex) const {
GeodeticPatch patch(tileIndex);
bool aboveEquator = patch.isNorthern();
double lat = aboveEquator ? patch.minLat() : patch.maxLat();
double lon1 = patch.minLon();
double lon2 = patch.maxLon();
int l = static_cast<int>(_ellipsoid.longitudalDistance(lat, lon1, lon2));
bool useKm = l > 9999;
if (useKm) l /= 1000;
l = std::round(l);
if (useKm) l *= 1000;
return l;
}
TileHashKey SizeReferenceTileProvider::toHash(const TileIndex& tileIndex) const {
int l = roundedLongitudalLength(tileIndex);
TileHashKey key = static_cast<TileHashKey>(l);
return key;
}
Tile SizeReferenceTileProvider::backgroundTile(const TileIndex& tileIndex) const {
if (_backgroundTile.status == Tile::Status::OK) {
Tile tile;
auto t = _backgroundTile.texture;
void* pixelData = new char[t->expectedPixelDataSize()];
memcpy(pixelData, t->pixelData(), t->expectedPixelDataSize());
tile.texture = std::make_shared<Texture>(
pixelData, t->dimensions(), t->format(), t->internalFormat(), t->dataType(), t->filter(), t->wrapping());
tile.texture->uploadTexture();
tile.texture->setDataOwnership(Texture::TakeOwnership::Yes);
tile.status = Tile::Status::OK;
return tile;
}
else {
// use default background
return TextTileProvider::backgroundTile(tileIndex);
}
else {
// use default background
return TextTileProvider::backgroundTile(tileIndex);
}
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,68 +1,55 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TEXT_TILE_PROVIDER_H__
#define __TEXT_TILE_PROVIDER_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TEXT_TILE_PROVIDER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TEXT_TILE_PROVIDER_H__
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <memory>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // absPath
#include <ghoul/opengl/texture.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/font/fontmanager.h>
#include <modules/globebrowsing/tile/asynctilereader.h>
#include <modules/globebrowsing/other/lrucache.h>
#include <modules/globebrowsing/geometry/ellipsoid.h>
//////////////////////////////////////////////////////////////////////////////////////////
// TILE PROVIDER //
//////////////////////////////////////////////////////////////////////////////////////////
namespace ghoul { namespace fontrendering {
class Font;
class FontRenderer;
}}
namespace openspace {
namespace globebrowsing {
using namespace ghoul::fontrendering;
/**
* Enables a simple way of providing tiles with any type of rendered text.
* Internally it handles setting up a FBO for rendering the text, and defines a new
* interface, consisting of only a single method for subclasses to implement:
* renderText(const FontRenderer&, const TileIndex&) const;
*/
* Enables a simple way of providing tiles with any type of rendered text.
* Internally it handles setting up a FBO for rendering the text, and defines a new
* interface, consisting of only a single method for subclasses to implement:
* renderText(const FontRenderer&, const TileIndex&) const;
*/
class TextTileProvider : public TileProvider {
public:
/**
* Default constructor with default values for texture and font size
*/
* Default constructor with default values for texture and font size
*/
TextTileProvider(const glm::uvec2& textureSize = {512, 512}, size_t fontSize = 48);
virtual ~TextTileProvider();
@@ -76,29 +63,29 @@ public:
virtual int maxLevel();
/**
* Returns the tile which will be used to draw text onto.
* Default implementation returns a tile with a plain transparent texture.
*/
* Returns the tile which will be used to draw text onto.
* Default implementation returns a tile with a plain transparent texture.
*/
virtual Tile backgroundTile(const TileIndex& tileIndex) const;
/**
* Allow overriding of hash function.
* Default is <code>TileIndex::hashKey()</code>
*
* \param tileIndex tileIndex to hash
* \returns hashkey used for in LRU cache for this tile
*/
* Allow overriding of hash function.
* Default is <code>TileIndex::hashKey()</code>
*
* \param tileIndex tileIndex to hash
* \returns hashkey used for in LRU cache for this tile
*/
virtual TileHashKey toHash(const TileIndex& tileIndex) const;
/**
* Uses the fontRenderer to render some text onto the tile texture provided in
* backgroundTile(const TileIndex& tileIndex).
*
* \param fontRenderer used for rendering text onto texture
* \param tileIndex associated with the tile to be rendered onto
*/
virtual void renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const = 0;
* Uses the fontRenderer to render some text onto the tile texture provided in
* backgroundTile(const TileIndex& tileIndex).
*
* \param fontRenderer used for rendering text onto texture
* \param tileIndex associated with the tile to be rendered onto
*/
virtual void renderText(const ghoul::fontrendering::FontRenderer& fontRenderer,
const TileIndex& tileIndex) const = 0;
protected:
std::shared_ptr<ghoul::fontrendering::Font> _font;
@@ -114,22 +101,24 @@ private:
};
/**
* Provides <code>Tile</code>s with the chunk index rendered as text onto its tiles.
*/
* Provides <code>Tile</code>s with the chunk index rendered as text onto its tiles.
*/
class TileIndexTileProvider : public TextTileProvider {
public:
virtual void renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const;
virtual void renderText(const ghoul::fontrendering::FontRenderer& fontRenderer,
const TileIndex& tileIndex) const;
};
/**
* Constructed with an ellipsoid and uses that to render the longitudal length of each
* of each tile.
*/
* Constructed with an ellipsoid and uses that to render the longitudal length of each
* of each tile.
*/
class SizeReferenceTileProvider : public TextTileProvider {
public:
SizeReferenceTileProvider(const ghoul::Dictionary& dictionary);
virtual void renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const;
virtual void renderText(const ghoul::fontrendering::FontRenderer& fontRenderer,
const TileIndex& tileIndex) const;
virtual Tile backgroundTile(const TileIndex& tileIndex) const;
virtual TileHashKey toHash(const TileIndex& tileIndex) const;
@@ -145,7 +134,4 @@ private:
} // namespace globebrowsing
} // namespace openspace
#endif // __TEXT_TILE_PROVIDER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TEXT_TILE_PROVIDER_H__

View File

@@ -1,35 +1,34 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <limits>
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <openspace/util/factorymanager.h>
#include <modules/globebrowsing/tile/chunktile.h>
#include <modules/globebrowsing/tile/tileselector.h>
#include <openspace/util/factorymanager.h>
#include <ghoul/misc/dictionary.h>
#include <ghoul/logging/logmanager.h>
namespace {
@@ -42,11 +41,9 @@ namespace openspace {
namespace globebrowsing {
TileProvider* TileProvider::createFromDictionary(const ghoul::Dictionary& dictionary) {
std::string type = "LRUCaching";
dictionary.getValue(KeyType, type);
ghoul::TemplateFactory<TileProvider>* factory
= FactoryManager::ref().factory<TileProvider>();
auto factory = FactoryManager::ref().factory<TileProvider>();
TileProvider* result = factory->create(type, dictionary);
if (result == nullptr) {
@@ -57,7 +54,7 @@ TileProvider* TileProvider::createFromDictionary(const ghoul::Dictionary& dictio
return result;
}
TileProvider::TileProvider(const ghoul::Dictionary& dictionary) { };
TileProvider::TileProvider(const ghoul::Dictionary& dictionary) {};
float TileProvider::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
@@ -77,12 +74,12 @@ ChunkTile TileProvider::getChunkTile(TileIndex tileIndex, int parents, int maxPa
// Step 2. Traverse 0 or more parents up the chunkTree to make sure we're inside
// the range of defined data.
int maximumLevel = maxLevel();
while(tileIndex.level > maximumLevel){
while (tileIndex.level > maximumLevel){
TileSelector::ascendToParent(tileIndex, uvTransform);
maxParents--;
}
if(maxParents < 0){
return{ Tile::TileUnavailable, uvTransform };
return { Tile::TileUnavailable, uvTransform };
}
// Step 3. Traverse 0 or more parents up the chunkTree until we find a chunk that
@@ -90,30 +87,32 @@ ChunkTile TileProvider::getChunkTile(TileIndex tileIndex, int parents, int maxPa
while (tileIndex.level > 1) {
Tile tile = getTile(tileIndex);
if (tile.status != Tile::Status::OK) {
if(--maxParents < 0){
if (--maxParents < 0){
return{ Tile::TileUnavailable, uvTransform };
}
TileSelector::ascendToParent(tileIndex, uvTransform);
}
else return { tile, uvTransform };
else {
return { tile, uvTransform };
}
}
return{ Tile::TileUnavailable, uvTransform };
return { Tile::TileUnavailable, uvTransform };
}
ChunkTilePile TileProvider::getChunkTilePile(TileIndex tileIndex, int pileSize){
ghoul_assert(pileSize >= 0, "pileSize must be positive");
ChunkTilePile chunkTilePile;
chunkTilePile.chunkTiles.resize(pileSize);
for (size_t i = 0; i < pileSize; ++i){
for (size_t i = 0; i < pileSize; ++i) {
chunkTilePile.chunkTiles[i] = getChunkTile(tileIndex, i);
if (chunkTilePile.chunkTiles[i].tile.status == Tile::Status::Unavailable) {
if(i>0){
if (i>0) {
chunkTilePile.chunkTiles[i].tile = chunkTilePile.chunkTiles[i-1].tile;
chunkTilePile.chunkTiles[i].uvTransform.uvOffset = chunkTilePile.chunkTiles[i-1].uvTransform.uvOffset;
chunkTilePile.chunkTiles[i].uvTransform.uvScale = chunkTilePile.chunkTiles[i-1].uvTransform.uvScale;
}
else{
else {
chunkTilePile.chunkTiles[i].tile = getDefaultTile();
chunkTilePile.chunkTiles[i].uvTransform.uvOffset = { 0, 0 };
chunkTilePile.chunkTiles[i].uvTransform.uvScale = { 1, 1 };

View File

@@ -1,163 +1,149 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_PROVIDER_H__
#define __TILE_PROVIDER_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_H__
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/filesystem/filesystem.h> // absPath
#include <ghoul/opengl/texture.h>
#include <ghoul/misc/dictionary.h>
#include <modules/globebrowsing/tile/tiledepthtransform.h>
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/other/lrucache.h>
#include <modules/globebrowsing/tile/chunktile.h>
#include <modules/globebrowsing/tile/tile.h>
#include <modules/globebrowsing/other/lrucache.h>
//////////////////////////////////////////////////////////////////////////////////////////
// TILE PROVIDER //
//////////////////////////////////////////////////////////////////////////////////////////
#include <vector>
namespace openspace {
namespace globebrowsing {
using namespace ghoul::opengl;
/**
* Interface for providing <code>Tile</code>s given a
* <code>TileIndex</code>.
*/
* Interface for providing <code>Tile</code>s given a
* <code>TileIndex</code>.
*/
class TileProvider {
public:
/**
* Factory method for instantiating different implementations of
* <code>TileProviders</code>. The provided dictionary must
* define a key specifying what implementation of TileProvider
* to be instantiated.
*/
* Factory method for instantiating different implementations of
* <code>TileProviders</code>. The provided dictionary must
* define a key specifying what implementation of TileProvider
* to be instantiated.
*/
static TileProvider* createFromDictionary(const ghoul::Dictionary& dictionary);
/**
* Empty default constructor
*/
TileProvider() {};
* Empty default constructor
*/
TileProvider() = default;
/**
* Implementations of the TileProvider interface must implement
* a constructor taking a dictionary as input. The provided
* dictionary must define a key specifying what implementation
* of TileProvider to be instantiated.
*/
* Implementations of the TileProvider interface must implement
* a constructor taking a dictionary as input. The provided
* dictionary must define a key specifying what implementation
* of TileProvider to be instantiated.
*/
TileProvider(const ghoul::Dictionary& dictionary);
/**
* Virtual destructor that subclasses should override to do
* clean up.
*/
* Virtual destructor that subclasses should override to do
* clean up.
*/
virtual ~TileProvider() { }
/**
* Method for querying tiles, given a specified <code>TileIndex</code>.
*
* This method is expected to be invoked multiple times per frame,
* and should therefore return quickly, e.g. not perform heavy I/O
* operations. However, invoking this method may spawn separate threads
* to perform such operations. Therefore, programmers shoud
* note that there is no guarantee that the <code>Tile</code>
* status and texture will be consistent over different invocations
* of this method.
*
* \param tileIndex specifying a region of a map for which
* we want tile data.
*
* \returns The tile corresponding to the TileIndex by the time
* the method was invoked.
*/
* Method for querying tiles, given a specified <code>TileIndex</code>.
*
* This method is expected to be invoked multiple times per frame,
* and should therefore return quickly, e.g. not perform heavy I/O
* operations. However, invoking this method may spawn separate threads
* to perform such operations. Therefore, programmers shoud
* note that there is no guarantee that the <code>Tile</code>
* status and texture will be consistent over different invocations
* of this method.
*
* \param tileIndex specifying a region of a map for which
* we want tile data.
*
* \returns The tile corresponding to the TileIndex by the time
* the method was invoked.
*/
virtual Tile getTile(const TileIndex& tileIndex) = 0;
virtual ChunkTile getChunkTile(TileIndex tileIndex, int parents = 0, int maxParents = 1337);
virtual ChunkTile getChunkTile(TileIndex tileIndex, int parents = 0,
int maxParents = 1337);
virtual ChunkTilePile getChunkTilePile(TileIndex tileIndex, int pileSize);
/**
* TileProviders must be able to provide a defualt
* <code>Tile</code> which may be used by clients in cases when
* requested tiles were unavailable.
*
* \returns A default tile
*/
* TileProviders must be able to provide a defualt
* <code>Tile</code> which may be used by clients in cases when
* requested tiles were unavailable.
*
* \returns A default tile
*/
virtual Tile getDefaultTile() = 0;
/**
* Returns the status of a <code>Tile</code>. The <code>Tile::Status</code>
* corresponds the <code>Tile</code> that would be returned
* if the function <code>getTile</code> would be invoked with the same
* <code>TileIndex</code> argument at this point in time.
*/
* Returns the status of a <code>Tile</code>. The <code>Tile::Status</code>
* corresponds the <code>Tile</code> that would be returned
* if the function <code>getTile</code> would be invoked with the same
* <code>TileIndex</code> argument at this point in time.
*/
virtual Tile::Status getTileStatus(const TileIndex& index) = 0;
/**
* Get the associated depth transform for this TileProvider.
* This is necessary for TileProviders serving height map
* data, in order to correcly map pixel values to meters.
*/
* Get the associated depth transform for this TileProvider.
* This is necessary for TileProviders serving height map
* data, in order to correcly map pixel values to meters.
*/
virtual TileDepthTransform depthTransform() = 0;
/**
* This method should be called once per frame. Here, TileProviders
* are given the opportunity to update their internal state.
*/
* This method should be called once per frame. Here, TileProviders
* are given the opportunity to update their internal state.
*/
virtual void update() = 0;
/**
* Provides a uniform way of all TileProviders to reload or
* restore all of its internal state. This is mainly useful
* for debugging purposes.
*/
* Provides a uniform way of all TileProviders to reload or
* restore all of its internal state. This is mainly useful
* for debugging purposes.
*/
virtual void reset() = 0;
/**
* \returns The maximum level as defined by <code>TileIndex</code>
* that this TileProvider is able provide.
*/
* \returns The maximum level as defined by <code>TileIndex</code>
* that this TileProvider is able provide.
*/
virtual int maxLevel() = 0;
/**
* \returns the no data value for the dataset. Default is the minimum float avalue.
*/
* \returns the no data value for the dataset. Default is the minimum float avalue.
*/
virtual float noDataValueAsFloat();
};
typedef LRUCache<TileHashKey, Tile> TileCache;
using TileCache = LRUCache<TileHashKey, Tile>;
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_PROVIDER_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_H__

View File

@@ -22,90 +22,96 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/engine/openspaceengine.h>
#include <ghoul/misc/dictionary.h>
namespace {
const std::string _loggerCat = "TileProviderByIndex";
const std::string KeyDefaultProvider = "DefaultProvider";
const std::string KeyProviders = "IndexTileProviders";
const std::string KeyTileIndex = "TileIndex";
const std::string KeyTileProvider = "TileProvider";
const char* KeyDefaultProvider = "DefaultProvider";
const char* KeyProviders = "IndexTileProviders";
const char* KeyTileIndex = "TileIndex";
const char* KeyTileProvider = "TileProvider";
}
namespace openspace {
namespace globebrowsing {
TileProviderByIndex::TileProviderByIndex(const ghoul::Dictionary& dictionary) {
ghoul::Dictionary defaultProviderDict = dictionary.value<ghoul::Dictionary>(KeyDefaultProvider);
TileProvider * defaultProvider = TileProvider::createFromDictionary(defaultProviderDict);
_defaultTileProvider = std::shared_ptr<TileProvider>(defaultProvider);
TileProviderByIndex::TileProviderByIndex(const ghoul::Dictionary& dictionary) {
ghoul::Dictionary defaultProviderDict = dictionary.value<ghoul::Dictionary>(
KeyDefaultProvider
);
TileProvider* defaultProvider = TileProvider::createFromDictionary(
defaultProviderDict
);
_defaultTileProvider = std::shared_ptr<TileProvider>(defaultProvider);
ghoul::Dictionary indexProvidersDict = dictionary.value<ghoul::Dictionary>(KeyProviders);
for (size_t i = 0; i < indexProvidersDict.size(); i++) {
std::string dictKey = std::to_string(i + 1);
ghoul::Dictionary indexProviderDict = indexProvidersDict.value<ghoul::Dictionary>(dictKey);
ghoul::Dictionary tileIndexDict = indexProviderDict.value<ghoul::Dictionary>(KeyTileIndex);
ghoul::Dictionary providerDict = indexProviderDict.value<ghoul::Dictionary>(KeyTileProvider);
ghoul::Dictionary indexProvidersDict = dictionary.value<ghoul::Dictionary>(
KeyProviders
);
for (size_t i = 0; i < indexProvidersDict.size(); i++) {
std::string dictKey = std::to_string(i + 1);
ghoul::Dictionary indexProviderDict = indexProvidersDict.value<ghoul::Dictionary>(
dictKey
);
ghoul::Dictionary tileIndexDict = indexProviderDict.value<ghoul::Dictionary>(
KeyTileIndex
);
ghoul::Dictionary providerDict = indexProviderDict.value<ghoul::Dictionary>(
KeyTileProvider
);
TileIndex tileIndex(tileIndexDict);
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
std::shared_ptr<TileProvider> stp = std::shared_ptr<TileProvider>(tileProvider);
TileHashKey key = tileIndex.hashKey();
_tileProviderMap.insert(std::make_pair(key, stp));
}
TileIndex tileIndex(tileIndexDict);
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
std::shared_ptr<TileProvider> stp = std::shared_ptr<TileProvider>(tileProvider);
TileHashKey key = tileIndex.hashKey();
_tileProviderMap.insert(std::make_pair(key, stp));
}
}
Tile TileProviderByIndex::getTile(const TileIndex& tileIndex) {
auto it = _tileProviderMap.find(tileIndex.hashKey());
bool hasProvider = it != _tileProviderMap.end();
return hasProvider ? it->second->getTile(tileIndex) : Tile::TileUnavailable;
}
Tile TileProviderByIndex::getTile(const TileIndex& tileIndex) {
auto it = _tileProviderMap.find(tileIndex.hashKey());
bool hasProvider = it != _tileProviderMap.end();
return hasProvider ? it->second->getTile(tileIndex) : Tile::TileUnavailable;
}
Tile TileProviderByIndex::getDefaultTile() {
return _defaultTileProvider->getDefaultTile();
}
Tile TileProviderByIndex::getDefaultTile() {
return _defaultTileProvider->getDefaultTile();
}
Tile::Status TileProviderByIndex::getTileStatus(const TileIndex& tileIndex) {
auto it = _tileProviderMap.find(tileIndex.hashKey());
bool hasProvider = it != _tileProviderMap.end();
return hasProvider ? it->second->getTileStatus(tileIndex) : Tile::Status::Unavailable;
}
Tile::Status TileProviderByIndex::getTileStatus(const TileIndex& tileIndex) {
auto it = _tileProviderMap.find(tileIndex.hashKey());
bool hasProvider = it != _tileProviderMap.end();
return hasProvider ? it->second->getTileStatus(tileIndex) : Tile::Status::Unavailable;
}
TileDepthTransform TileProviderByIndex::depthTransform() {
return _defaultTileProvider->depthTransform();
}
TileDepthTransform TileProviderByIndex::depthTransform() {
return _defaultTileProvider->depthTransform();
}
void TileProviderByIndex::update() {
for(auto it : _tileProviderMap){
it.second->update();
}
_defaultTileProvider->update();
void TileProviderByIndex::update() {
for (auto& it : _tileProviderMap){
it.second->update();
}
_defaultTileProvider->update();
}
void TileProviderByIndex::reset() {
for(auto it : _tileProviderMap){
it.second->reset();
}
_defaultTileProvider->reset();
void TileProviderByIndex::reset() {
for (auto& it : _tileProviderMap) {
it.second->reset();
}
_defaultTileProvider->reset();
}
int TileProviderByIndex::maxLevel() {
return _defaultTileProvider->maxLevel();
}
int TileProviderByIndex::maxLevel() {
return _defaultTileProvider->maxLevel();
}
TileProvider* TileProviderByIndex::indexProvider(const TileIndex& tileIndex) const{
auto it = _tileProviderMap.find(tileIndex.hashKey());
return (it != _tileProviderMap.end()) ? it->second.get() : nullptr;
}
TileProvider* TileProviderByIndex::indexProvider(const TileIndex& tileIndex) const {
auto it = _tileProviderMap.find(tileIndex.hashKey());
return (it != _tileProviderMap.end()) ? it->second.get() : nullptr;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,75 +1,57 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_PROVIDER_BY_INDEX__
#define __TILE_PROVIDER_BY_INDEX__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_INDEX_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_INDEX_H__
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/asynctilereader.h>
#include <gdal_priv.h>
#include <openspace/engine/downloadmanager.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // absPath
#include <ghoul/opengl/texture.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/font/fontrenderer.h>
#include <unordered_map>
namespace openspace {
namespace globebrowsing {
using namespace ghoul::opengl;
class TileProviderByIndex : public TileProvider {
public:
TileProviderByIndex(const ghoul::Dictionary& dictionary);
TileProviderByIndex(const std::string& imagePath);
virtual ~TileProviderByIndex() { }
class TileProviderByIndex : public TileProvider {
public:
TileProviderByIndex(const ghoul::Dictionary& dictionary);
TileProviderByIndex(const std::string& imagePath);
virtual ~TileProviderByIndex() { }
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& index);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& index);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
private:
TileProvider* indexProvider(const TileIndex& tileIndex) const;
private:
inline TileProvider* indexProvider(const TileIndex& tileIndex) const;
std::unordered_map<TileHashKey, std::shared_ptr<TileProvider>> _tileProviderMap;
std::shared_ptr<TileProvider> _defaultTileProvider;
};
std::unordered_map<TileHashKey, std::shared_ptr<TileProvider>> _tileProviderMap;
std::shared_ptr<TileProvider> _defaultTileProvider;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_PROVIDER_BY_INDEX__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_INDEX_H__

View File

@@ -1,129 +1,132 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/engine/openspaceengine.h>
#include <ghoul/misc/dictionary.h>
namespace {
const std::string _loggerCat = "TileProviderByLevel";
const std::string KeyProviders = "LevelTileProviders";
const std::string KeyMaxLevel = "MaxLevel";
const std::string KeyTileProvider = "TileProvider";
const char* KeyProviders = "LevelTileProviders";
const char* KeyMaxLevel = "MaxLevel";
const char* KeyTileProvider = "TileProvider";
}
namespace openspace {
namespace globebrowsing {
TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) {
TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) {
ghoul::Dictionary levelProvidersDict = dictionary.value<ghoul::Dictionary>(
KeyProviders
);
for (size_t i = 0; i < levelProvidersDict.size(); i++) {
std::string dictKey = std::to_string(i + 1);
ghoul::Dictionary levelProviderDict = levelProvidersDict.value<ghoul::Dictionary>(
dictKey
);
double floatMaxLevel;
int maxLevel = 0;
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
throw std::runtime_error(
"Must define key '" + std::string(KeyMaxLevel) + "'"
);
}
maxLevel = std::round(floatMaxLevel);
ghoul::Dictionary providerDict;
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict))
{
throw std::runtime_error(
"Must define key '" + std::string(KeyTileProvider) + "'"
);
}
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
_levelTileProviders.push_back(std::shared_ptr<TileProvider>(tileProvider));
// Ensure we can represent the max level
if(_providerIndices.size() < maxLevel){
_providerIndices.resize(maxLevel+1, -1);
}
// map this level to the tile provider index
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
}
ghoul::Dictionary levelProvidersDict = dictionary.value<ghoul::Dictionary>(KeyProviders);
for (size_t i = 0; i < levelProvidersDict.size(); i++) {
std::string dictKey = std::to_string(i + 1);
ghoul::Dictionary levelProviderDict = levelProvidersDict.value<ghoul::Dictionary>(dictKey);
double floatMaxLevel;
int maxLevel = 0;
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
throw std::runtime_error("Must define key '" + KeyMaxLevel + "'");
}
maxLevel = std::round(floatMaxLevel);
ghoul::Dictionary providerDict;
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict)) {
throw std::runtime_error("Must define key '" + KeyTileProvider + "'");
}
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
_levelTileProviders.push_back(std::shared_ptr<TileProvider>(tileProvider));
// Ensure we can represent the max level
if(_providerIndices.size() < maxLevel){
_providerIndices.resize(maxLevel+1, -1);
}
// map this level to the tile provider index
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
}
// Fill in the gaps (value -1) in provider indices, from back to end
for(int i = _providerIndices.size() - 2; i>=0; --i){
if(_providerIndices[i] == -1){
_providerIndices[i] = _providerIndices[i+1];
}
// Fill in the gaps (value -1) in provider indices, from back to end
for(int i = _providerIndices.size() - 2; i >= 0; --i){
if(_providerIndices[i] == -1){
_providerIndices[i] = _providerIndices[i+1];
}
}
}
Tile TileProviderByLevel::getTile(const TileIndex& tileIndex) {
return levelProvider(tileIndex.level)->getTile(tileIndex);
}
Tile TileProviderByLevel::getTile(const TileIndex& tileIndex) {
return levelProvider(tileIndex.level)->getTile(tileIndex);
}
Tile TileProviderByLevel::getDefaultTile() {
return levelProvider(0)->getDefaultTile();
}
Tile TileProviderByLevel::getDefaultTile() {
return levelProvider(0)->getDefaultTile();
}
Tile::Status TileProviderByLevel::getTileStatus(const TileIndex& index) {
return levelProvider(index.level)->getTileStatus(index);
}
Tile::Status TileProviderByLevel::getTileStatus(const TileIndex& index) {
return levelProvider(index.level)->getTileStatus(index);
}
TileDepthTransform TileProviderByLevel::depthTransform() {
TileDepthTransform transform;
transform.depthOffset = 0.0f;
transform.depthScale = 1.0f;
return transform;
}
TileDepthTransform TileProviderByLevel::depthTransform() {
TileDepthTransform transform;
transform.depthOffset = 0.0f;
transform.depthScale = 1.0f;
return transform;
}
void TileProviderByLevel::update() {
for(auto provider : _levelTileProviders){
provider->update();
}
void TileProviderByLevel::update() {
for(auto provider : _levelTileProviders){
provider->update();
}
}
void TileProviderByLevel::reset() {
for(auto provider : _levelTileProviders){
provider->reset();
}
void TileProviderByLevel::reset() {
for(auto provider : _levelTileProviders){
provider->reset();
}
}
int TileProviderByLevel::maxLevel() {
return _providerIndices.size()-1;
}
int TileProviderByLevel::maxLevel() {
return _providerIndices.size()-1;
}
int TileProviderByLevel::providerIndex(int level) const {
int clampedLevel = std::max(0, std::min(level, (int)_providerIndices.size()-1));
return _providerIndices[clampedLevel];
}
int TileProviderByLevel::providerIndex(int level) const {
int clampedLevel = std::max(0, std::min(level, (int)_providerIndices.size()-1));
return _providerIndices[clampedLevel];
}
TileProvider* TileProviderByLevel::levelProvider(int level) const{
return _levelTileProviders[providerIndex(level)].get();
}
TileProvider* TileProviderByLevel::levelProvider(int level) const {
return _levelTileProviders[providerIndex(level)].get();
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,74 +1,57 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_PROVIDER_BY_LEVEL__
#define __TILE_PROVIDER_BY_LEVEL__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_LEVEL_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_LEVEL_H__
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/asynctilereader.h>
#include <gdal_priv.h>
#include <openspace/engine/downloadmanager.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // absPath
#include <ghoul/opengl/texture.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/font/fontrenderer.h>
#include <set>
namespace openspace {
namespace globebrowsing {
using namespace ghoul::opengl;
class TileProviderByLevel : public TileProvider {
public:
TileProviderByLevel(const ghoul::Dictionary& dictionary);
TileProviderByLevel(const std::string& imagePath);
virtual ~TileProviderByLevel() { }
class TileProviderByLevel : public TileProvider {
public:
TileProviderByLevel(const ghoul::Dictionary& dictionary);
TileProviderByLevel(const std::string& imagePath);
virtual ~TileProviderByLevel() { }
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& index);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
private:
inline int providerIndex(int level) const;
inline TileProvider* levelProvider(int level) const;
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& index);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
private:
inline int providerIndex(int level) const;
inline TileProvider* levelProvider(int level) const;
std::vector<int> _providerIndices;
std::vector<std::shared_ptr<TileProvider>> _levelTileProviders;
};
std::vector<int> _providerIndices;
std::vector<std::shared_ptr<TileProvider>> _levelTileProviders;
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_PROVIDER_BY_LEVEL__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_LEVEL_H__

View File

@@ -1,89 +1,84 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/tile/tileselector.h>
#include <modules/globebrowsing/rendering/layermanager.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <sstream>
#include <algorithm>
#include "gdal_priv.h"
namespace {
const std::string _loggerCat = "TileSelector";
}
namespace openspace {
namespace globebrowsing {
const TileSelector::CompareResolution TileSelector::HIGHEST_RES = TileSelector::CompareResolution();
ChunkTile TileSelector::getHighestResolutionTile(const LayerGroup& layerGroup,
TileIndex tileIndex)
{
ChunkTile mostHighResolution;
mostHighResolution.tile = Tile::TileUnavailable;
mostHighResolution.uvTransform.uvScale.x = 0;
ChunkTile TileSelector::getHighestResolutionTile(const LayerGroup& layerGroup, TileIndex tileIndex) {
ChunkTile mostHighResolution;
mostHighResolution.tile = Tile::TileUnavailable;
mostHighResolution.uvTransform.uvScale.x = 0;
for (const auto& layer : layerGroup.activeLayers()) {
ChunkTile chunkTile = layer->tileProvider()->getChunkTile(tileIndex);
bool tileIsOk = chunkTile.tile.status == Tile::Status::OK;
bool tileHasMetaData = chunkTile.tile.metaData != nullptr;
bool tileIsHigherResolution = chunkTile.uvTransform.uvScale.x > mostHighResolution.uvTransform.uvScale.x;
if (tileIsOk && tileHasMetaData && tileIsHigherResolution) {
mostHighResolution = chunkTile;
}
for (const auto& layer : layerGroup.activeLayers()) {
ChunkTile chunkTile = layer->tileProvider()->getChunkTile(tileIndex);
bool tileIsOk = chunkTile.tile.status == Tile::Status::OK;
bool tileHasMetaData = chunkTile.tile.metaData != nullptr;
bool tileIsHigherResolution =
chunkTile.uvTransform.uvScale.x > mostHighResolution.uvTransform.uvScale.x;
if (tileIsOk && tileHasMetaData && tileIsHigherResolution) {
mostHighResolution = chunkTile;
}
return mostHighResolution;
}
bool TileSelector::CompareResolution::operator()(const ChunkTile& a, const ChunkTile& b) {
// large uv scale means smaller resolution
return a.uvTransform.uvScale.x > b.uvTransform.uvScale.x;
return mostHighResolution;
}
std::vector<ChunkTile> TileSelector::getTilesSortedByHighestResolution(
const LayerGroup& layerGroup,
const TileIndex& tileIndex)
{
std::vector<ChunkTile> tiles;
for (const auto& layer : layerGroup.activeLayers()) {
tiles.push_back(layer->tileProvider()->getChunkTile(tileIndex));
}
std::vector<ChunkTile> TileSelector::getTilesSortedByHighestResolution(const LayerGroup& layerGroup, const TileIndex& tileIndex) {
std::vector<ChunkTile> tiles;
for (const auto& layer : layerGroup.activeLayers()) {
tiles.push_back(layer->tileProvider()->getChunkTile(tileIndex));
std::sort(
tiles.begin(),
tiles.end(),
[](const ChunkTile& lhs, const ChunkTile& rhs) {
return lhs.uvTransform.uvScale.x > rhs.uvTransform.uvScale.x;
}
);
std::sort(tiles.begin(), tiles.end(), TileSelector::HIGHEST_RES);
return tiles;
}
return tiles;
}
void TileSelector::ascendToParent(TileIndex& tileIndex, TileUvTransform& uv) {
uv.uvOffset *= 0.5;
uv.uvScale *= 0.5;
void TileSelector::ascendToParent(TileIndex& tileIndex, TileUvTransform& uv) {
uv.uvOffset *= 0.5;
uv.uvScale *= 0.5;
uv.uvOffset += tileIndex.positionRelativeParent();
uv.uvOffset += tileIndex.positionRelativeParent();
--tileIndex;
}
--tileIndex;
}
} // namespace globebrowsing
} // namespace openspace

View File

@@ -1,59 +1,52 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __TILE_SELECTOR_H__
#define __TILE_SELECTOR_H__
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_SELECTOR_H__
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_SELECTOR_H__
#include <modules/globebrowsing/rendering/layermanager.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <modules/globebrowsing/tile/chunktile.h>
#include <modules/globebrowsing/tile/tile.h>
#include <vector>
namespace openspace {
namespace globebrowsing {
//struct LayerGroup;
class TileProvider;
struct LayerGroup;
class TileProvider;
class TileSelector {
public:
static ChunkTile getHighestResolutionTile(const LayerGroup& layerGroup, TileIndex tileIndex);
static std::vector<ChunkTile> getTilesSortedByHighestResolution(const LayerGroup& layerGroup, const TileIndex& tileIndex);
class TileSelector {
public:
static ChunkTile getHighestResolutionTile(const LayerGroup& layerGroup,
TileIndex tileIndex);
static std::vector<ChunkTile> getTilesSortedByHighestResolution(
const LayerGroup& layerGroup, const TileIndex& tileIndex);
struct CompareResolution {
bool operator() (const ChunkTile& a, const ChunkTile& b);
};
static const CompareResolution HIGHEST_RES;
static void ascendToParent(TileIndex& tileIndex, TileUvTransform& uv);
};
static void ascendToParent(TileIndex& tileIndex, TileUvTransform& uv);
};
} // namespace globebrowsing
} // namespace openspace
#endif // __TILE_SELECTOR_H__
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_SELECTOR_H__

View File

@@ -7,9 +7,9 @@ return {
-- Sets the scene that is to be loaded by OpenSpace. A scene file is a description
-- of all entities that will be visible during an instance of OpenSpace
Scene = "${SCENE}/default.scene",
-- Scene = "${SCENE}/default.scene",
-- Scene = "${SCENE}/globebrowsing.scene",
Scene = "${SCENE}/globebrowsing.scene",
-- Scene = "${SCENE}/rosetta.scene",
-- Scene = "${SCENE}/dawn.scene",
-- Scene = "${SCENE}/newhorizons.scene",

View File

@@ -220,7 +220,10 @@ void InteractionHandler::goToGeo(double latitude, double longitude) {
std::dynamic_pointer_cast<GlobeBrowsingInteractionMode> (_currentInteractionMode);
if (gbim) {
gbim->goToGeodetic2(*_camera, globebrowsing::Geodetic2(latitude, longitude) / 180 * M_PI, true);
gbim->goToGeodetic2(
*_camera,
globebrowsing::Geodetic2(latitude, longitude) / 180 * glm::pi<double>(), true
);
} else {
LWARNING("Interaction mode must be set to 'GlobeBrowsing'");
}

View File

@@ -46,7 +46,7 @@ struct TestJob : public openspace::globebrowsing::Job<int> {
std::cout << "Finished job" << std::endl;
}
virtual std::shared_ptr<int> product() {
virtual std::shared_ptr<int> product() const {
return std::make_shared<int>(prod);
}
@@ -117,7 +117,7 @@ struct VerboseJob : public openspace::globebrowsing::Job<VerboseProduct>{
std::cout << " ** Finished job" << std::endl;
}
virtual std::shared_ptr<VerboseProduct> product() {
virtual std::shared_ptr<VerboseProduct> product() const {
return _product;
}

View File

@@ -41,7 +41,7 @@ TEST_F(ConvexHull2Test, basic) {
// 0 x x
// -1 0 1
std::vector<Point2> points = {
std::vector<glm::vec2> points = {
{ -1.0, 0.0 },
{ 1.0, 0.0 },
{ 0.0, 2.0 },
@@ -66,7 +66,7 @@ TEST_F(ConvexHull2Test, basic) {
TEST_F(ConvexHull2Test, intersection) {
using namespace openspace::globebrowsing;
std::vector<Point2> points1 = {
std::vector<glm::vec2> points1 = {
{ -1.0, 0.0 },
{ 1.0, 0.0 },
{ 0.0, 2.0 },
@@ -74,7 +74,7 @@ TEST_F(ConvexHull2Test, intersection) {
};
ConvexHull2 hull1 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points1);
std::vector<Point2> points2 = {
std::vector<glm::vec2> points2 = {
{ 0.0, 0.0 },
{ 2.0, 0.0 },
{ 1.0, 2.0 },
@@ -96,14 +96,14 @@ TEST_F(ConvexHull2Test, intersection) {
TEST_F(ConvexHull2Test, non_intersection) {
using namespace openspace::globebrowsing;
std::vector<Point2> points1 = {
std::vector<glm::vec2> points1 = {
{ -2.0, 0.0 },
{ 2.0, 0.0 },
{ 0.0, 2.0 },
};
ConvexHull2 hull1 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points1);
std::vector<Point2> points2 = {
std::vector<glm::vec2> points2 = {
{ 1.0, 2.0 },
{ 3.0, 0.0 },
{ 5.0, 2.0 }