Skip to content

Commit

Permalink
Merge pull request #22 from Klebert-Engineering/feature/viewport-driv…
Browse files Browse the repository at this point in the history
…en-updates

Viewport-Driven Tile Rendering
  • Loading branch information
josephbirkner committed Sep 28, 2023
2 parents 8171987 + 1ff8c90 commit cb9b0d0
Show file tree
Hide file tree
Showing 21 changed files with 1,094 additions and 607 deletions.
2 changes: 1 addition & 1 deletion libs/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
add_executable(erdblick-core ${ERDBLICK_SOURCE_FILES})
set_target_properties(erdblick-core PROPERTIES LINK_FLAGS "\
--bind \
--profiling \
-s ENVIRONMENT=web \
-s MODULARIZE=1 \
-s EXPORT_ES6=1 \
Expand Down Expand Up @@ -52,4 +53,3 @@ target_link_libraries(erdblick-core
glm
mapget-model
yaml-cpp)

30 changes: 18 additions & 12 deletions libs/core/include/erdblick/aabb.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ using Wgs84Point = mapget::Point;
class Wgs84AABB
{
public:
static TilePriorityFn radialDistancePrioFn(glm::vec2 camPos, float orientation);

using vec2_t = glm::dvec2;

Wgs84AABB() = default;
Expand Down Expand Up @@ -58,8 +56,9 @@ class Wgs84AABB
/** Obtain the size of this bounding box. */
vec2_t const& size() const { return size_; }

/** Determine whether the horizontal extent of this bounding rect
* crosses the anti-meridian (lon == +/- 180°).
/**
* Determine whether the horizontal extent of this bounding rect
* crosses the anti-meridian (lon == +/- 180°).
*/
bool containsAntiMeridian() const;

Expand Down Expand Up @@ -93,17 +92,24 @@ class Wgs84AABB
/** Determine whether this bounding rect has an intersection with another bounding rect. */
bool intersects(Wgs84AABB const& other) const;

/** Obtain TileIds for a given tile level.
/**
* Obtain TileIds for a given tile level. Will fill in tileIds for the
* given level into resultTileIdsWithPriority up to resultTileIdsWithPriority.capacity(),
* so the function is guaranteed not to allocate any heap memory.
* Also annotates each returned TileId with a float as returned by the
* TilePenaltyFn lambda.
*/
void tileIds(uint16_t level, std::vector<TileId> &result) const;
void tileIdsWithPriority(
uint16_t level,
std::vector<std::pair<TileId, float>> &resultTileIdsWithPriority,
TilePriorityFn const& prioFn) const;

/** Same as tileIdsWithPriority, but strips the priority values
* and converts the linked list to a vector.
/**
* Returns a tile priority function based on the given camera position
* in WGS84, and orientation (bearing) in Radians. This priority function
* may be plugged into tileIdsWithPriority.
*/
std::vector<TileId> tileIds(
uint16_t level,
std::function<double(TileId const&)> const& tilePenaltyFun,
size_t limit) const;
static TilePriorityFn radialDistancePrioFn(glm::vec2 const& camPos, float orientation);

private:
vec2_t sw_{.0, .0};
Expand Down
6 changes: 4 additions & 2 deletions libs/core/include/erdblick/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ class FeatureLayerRenderer
FeatureLayerRenderer();

/**
* Convert a TileFeatureLayer to a GLB buffer.
* Returns the cartesian origin of the tile.
* Convert a TileFeatureLayer to a GLB buffer. Returns the
* cartesian origin of the tile. If there are no features to render,
* either because the layer is empty or because no style rule matched,
* then the size of the result buffer will be zero.
*/
mapget::Point render(
const FeatureLayerStyle& style,
Expand Down
44 changes: 41 additions & 3 deletions libs/core/include/erdblick/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,51 @@ namespace erdblick
class TileLayerParser
{
public:
explicit TileLayerParser(SharedUint8Array const& dataSourceInfo);
void onTileParsed(std::function<void(mapget::TileFeatureLayer::Ptr)>);
void parse(SharedUint8Array const& dataSourceInfo);
explicit TileLayerParser();

/**
* Update the data source info metadata which the parser uses
* to supply parsed TileFeatureLayers with map metadata info.
*/
void setDataSourceInfo(SharedUint8Array const& dataSourceInfoJson);

/**
* Serialize a TileFeatureLayer to a buffer.
*/
void writeTileFeatureLayer(mapget::TileFeatureLayer::Ptr const& tile, SharedUint8Array& buffer);

/**
* Parse a TileFeatureLayer from a buffer as returned by writeTileFeatureLayer.
*/
mapget::TileFeatureLayer::Ptr readTileFeatureLayer(SharedUint8Array const& buffer);

/**
* Reset the parser by removing any buffered unparsed stream chunks.
*/
void reset();

/**
* Access the field id dictionary offsets as currently known by this parser.
* This is used to tell the server whether additional field-id mapping updates
* need to be sent.
*/
mapget::TileLayerStream::FieldOffsetMap fieldDictOffsets();

/**
* Stream-based parsing functionality: Set callback which is called
* as soon as a tile has been parsed.
*/
void onTileParsedFromStream(std::function<void(mapget::TileFeatureLayer::Ptr)>);

/**
* Add a chunk of streamed data into this TileLayerParser.
*/
void parseFromStream(SharedUint8Array const& buffer);

private:
std::map<std::string, mapget::DataSourceInfo> info_;
std::unique_ptr<mapget::TileLayerStream::Reader> reader_;
std::shared_ptr<mapget::TileLayerStream::CachedFieldsProvider> cachedFieldDicts_;
std::function<void(mapget::TileFeatureLayer::Ptr)> tileParsedFun_;
};

Expand Down
59 changes: 18 additions & 41 deletions libs/core/src/aabb.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "aabb.h"

#include "glm/ext.hpp"

namespace erdblick
{

Expand All @@ -16,33 +18,6 @@ inline Wgs84Point point(glm::dvec3 const& p)
return {p.x, p.y, p.z};
}

float fastAtan2(float y, float x)
{
if (x == 0.0 && y == 0.0) {
return 0.0; // handle the case when both x and y are zero
}

float abs_x = std::abs(x);
float abs_y = std::abs(y);

float a = std::min(abs_x, abs_y) / std::max(abs_x, abs_y);
float s = a * a;

float r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a;

if (abs_y > abs_x) {
r = 1.57079637f - r;
}
if (x < 0.0) {
r = 3.14159274f - r;
}
if (y < 0.0) {
r = -r;
}

return r;
}

} // namespace

Wgs84AABB::Wgs84AABB(const Wgs84Point& sw, glm::dvec2 size) : sw_(sw.x, sw.y), size_(size)
Expand Down Expand Up @@ -165,15 +140,18 @@ bool Wgs84AABB::intersects(const Wgs84AABB& other) const
contains(other.nw()) || other.intersects(*this);
}

void Wgs84AABB::tileIds(uint16_t level, std::vector<TileId>& tileIdsResult) const
void Wgs84AABB::tileIdsWithPriority(
uint16_t level,
std::vector<std::pair<TileId, float>> &tileIdsResult,
TilePriorityFn const& prioFn) const
{
if (containsAntiMeridian()) {
auto normalizedViewports = splitOverAntiMeridian();
assert(
!normalizedViewports.first.containsAntiMeridian() &&
!normalizedViewports.second.containsAntiMeridian());
normalizedViewports.first.tileIds(level, tileIdsResult);
normalizedViewports.second.tileIds(level, tileIdsResult);
normalizedViewports.first.tileIdsWithPriority(level, tileIdsResult, prioFn);
normalizedViewports.second.tileIdsWithPriority(level, tileIdsResult, prioFn);
}

auto const tileWidth = 180. / static_cast<double>(1 << level);
Expand All @@ -191,31 +169,30 @@ void Wgs84AABB::tileIds(uint16_t level, std::vector<TileId>& tileIdsResult) cons
double y = minPoint.y;
while (y <= maxPoint.y && remainingCapacity > 0) {
auto tid = TileId::fromWgs84(x, y, level);
tileIdsResult.emplace_back(tid);
tileIdsResult.emplace_back(tid, prioFn(tid));
remainingCapacity -= 1;
y += glm::min(tileWidth, glm::max(maxPoint.y - y, epsilon));
}
x += glm::min(tileWidth, glm::max(maxPoint.x - x, epsilon));
}
}

TilePriorityFn Wgs84AABB::radialDistancePrioFn(glm::vec2 camPos, float orientation)
TilePriorityFn Wgs84AABB::radialDistancePrioFn(glm::vec2 const& camPos, float orientation)
{
return [camPos, orientation](TileId const& tid)
{
auto center = tid.center();
float xDiff = center.x - camPos.x;
float yDiff = center.y - camPos.y;
float xDiff = static_cast<float>(center.x) - camPos.x;
float yDiff = static_cast<float>(center.y) - camPos.y;
auto angle = glm::atan(yDiff, xDiff); // Angle to east (x axis) direction. glm::atan is atan2.

angle -= orientation +
M_PI_2; // Difference w/ compass direction normalized from North to East
angle = glm::abs(glm::mod(angle, (float)M_2_PI)); // Map angle to circle
if (angle > M_PI)
angle = M_2_PI - angle;
angle -= orientation + glm::two_pi<float>(); // Difference w/ compass direction normalized from North to East
angle = glm::abs(glm::mod(angle, glm::two_pi<float>())); // Map angle to circle
if (angle > glm::pi<float>())
angle = glm::two_pi<float>() - angle;

auto distance = yDiff + xDiff; // eventually use manhattan distance to avoid comp overhead?
return yDiff + xDiff + angle * distance;
auto distance = glm::sqrt(yDiff*yDiff + xDiff*xDiff);
return distance + angle * distance;
};
}

Expand Down
Loading

0 comments on commit cb9b0d0

Please sign in to comment.