create async() function
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <llmr/util/vec.hpp>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
@@ -25,7 +26,7 @@ class BucketDescription;
|
||||
|
||||
|
||||
|
||||
class Tile {
|
||||
class Tile : public std::enable_shared_from_this<Tile> {
|
||||
public:
|
||||
struct exception : std::exception {};
|
||||
struct geometry_too_long_exception : exception {};
|
||||
@@ -52,8 +53,10 @@ public:
|
||||
Tile& operator=(const Tile&) = delete;
|
||||
Tile& operator=(const Tile && ) = delete;
|
||||
|
||||
// Start loading the tile.
|
||||
void request();
|
||||
|
||||
// Other functions
|
||||
void setData(uint8_t *data, uint32_t bytes);
|
||||
bool parse();
|
||||
void parseStyleLayers(const std::vector<LayerDescription>& layers);
|
||||
std::shared_ptr<Bucket> createBucket(const BucketDescription& bucket_desc);
|
||||
@@ -83,11 +86,10 @@ public:
|
||||
|
||||
private:
|
||||
// Source data
|
||||
uint8_t *data;
|
||||
uint32_t bytes;
|
||||
std::vector<char> data;
|
||||
VectorTile tile;
|
||||
|
||||
std::mutex mtx;
|
||||
// std::mutex mtx;
|
||||
|
||||
const Style& style;
|
||||
};
|
||||
|
||||
@@ -15,12 +15,6 @@ namespace platform {
|
||||
// controlling application.
|
||||
void restart(void *obj);
|
||||
|
||||
// Download a tile. Obtain the z/x/y from the tile shared_ptr.
|
||||
// You should perform the download and parsing of the tile in a separate thread!
|
||||
// Then, call map.tileLoaded(tile); or map.tileFailed(tile); in the main thread.
|
||||
void request(void *obj, std::shared_ptr<Tile> tile);
|
||||
|
||||
|
||||
struct Response {
|
||||
Response(int16_t code, const char *body, size_t length)
|
||||
: code(code),
|
||||
@@ -33,6 +27,8 @@ struct Response {
|
||||
|
||||
void request_http(std::string url, std::function<void(const Response&)> func);
|
||||
|
||||
void async(std::function<void()> fn, std::function<void()> cb);
|
||||
|
||||
// Returns a relative timestamp in seconds. This value must be monotonic.
|
||||
double time();
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#include <llmr/platform/platform.hpp>
|
||||
#include <llmr/map/tile.hpp>
|
||||
#include "settings.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
class MapView {
|
||||
public:
|
||||
MapView() :
|
||||
@@ -202,7 +203,6 @@ public:
|
||||
llmr::Map map;
|
||||
};
|
||||
|
||||
NSOperationQueue *queue = NULL;
|
||||
MapView *view;
|
||||
|
||||
namespace llmr {
|
||||
@@ -212,86 +212,36 @@ void restart(void *) {
|
||||
view->dirty = true;
|
||||
}
|
||||
|
||||
void request(void *, Tile::Ptr tile) {
|
||||
assert((bool)tile);
|
||||
|
||||
// NSString *urlTemplate = @"http://api.tiles.mapbox.com/v3/mapbox.mapbox-streets-v4/%d/%d/%d.vector.pbf";
|
||||
NSString *urlTemplate = @"http://localhost:3333/gl/tiles/plain/%d-%d-%d.vector.pbf";
|
||||
NSString *urlString = [NSString
|
||||
stringWithFormat:urlTemplate,
|
||||
tile->id.z,
|
||||
tile->id.x,
|
||||
tile->id.y];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
// NSLog(@"Requesting %@", urlString);
|
||||
|
||||
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
|
||||
|
||||
if (!queue) {
|
||||
queue = [[NSOperationQueue alloc] init];
|
||||
}
|
||||
|
||||
[NSURLConnection
|
||||
sendAsynchronousRequest:urlRequest
|
||||
queue:queue
|
||||
completionHandler: ^ (NSURLResponse * response,
|
||||
NSData * data,
|
||||
NSError * error) {
|
||||
if (error == nil) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
int code = [httpResponse statusCode];
|
||||
|
||||
if (code == 200) {
|
||||
tile->setData((uint8_t *)[data bytes], [data length]);
|
||||
if (tile->parse()) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
view->map.tileLoaded(tile);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// fall through to report tileFailed
|
||||
}
|
||||
// fall through to report tileFailed
|
||||
}
|
||||
// fall through to report tileFailed
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
view->map.tileFailed(tile);
|
||||
void async(std::function<void()> fn, std::function<void()> cb) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
|
||||
fn();
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void){
|
||||
cb();
|
||||
});
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void request_http(std::string url, std::function<void(const Response&)> func) {
|
||||
NSMutableURLRequest *urlRequest = [NSMutableURLRequest
|
||||
requestWithURL:[NSURL
|
||||
URLWithString:[NSString
|
||||
stringWithUTF8String:url.c_str()]]];
|
||||
|
||||
if (!queue) {
|
||||
queue = [[NSOperationQueue alloc] init];
|
||||
}
|
||||
|
||||
[NSURLConnection
|
||||
sendAsynchronousRequest:urlRequest
|
||||
queue:queue
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
completionHandler: ^ (NSURLResponse* response, NSData* data, NSError* error) {
|
||||
if (error == nil) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
func({
|
||||
[httpResponse statusCode],
|
||||
(const char *)[data bytes],
|
||||
[data length]
|
||||
});
|
||||
int code = [httpResponse statusCode];
|
||||
const char *body = (const char *)[data bytes];
|
||||
size_t length = [data length];
|
||||
func({ code, body, length });
|
||||
});
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
func({
|
||||
-1,
|
||||
0,
|
||||
0
|
||||
});
|
||||
func({ -1, 0, 0 });
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -132,7 +132,6 @@ Tile::Ptr Map::addTile(const Tile::ID& id) {
|
||||
// std::cerr << "init " << id.z << "/" << id.x << "/" << id.y << std::endl;
|
||||
// std::cerr << "add " << tile->toString() << std::endl;
|
||||
tiles.push_front(tile);
|
||||
historic_tiles.push_front(tile);
|
||||
}
|
||||
|
||||
return tile;
|
||||
@@ -252,8 +251,7 @@ void Map::updateTiles() {
|
||||
|
||||
if (tile->state == Tile::initial) {
|
||||
// If the tile is new, we have to make sure to load it.
|
||||
tile->state = Tile::loading;
|
||||
platform::request(this, tile);
|
||||
tile->request();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,16 +272,6 @@ void Map::updateTiles() {
|
||||
tiles.sort([](const Tile::Ptr& a, const Tile::Ptr& b) {
|
||||
return a->id.z > b->id.z;
|
||||
});
|
||||
|
||||
|
||||
// Remove all tiles that are only in the list of historic tiles. We do this
|
||||
// to make sure that the destructor (triggered by shared_ptr count falling
|
||||
// to 0) is triggered from the main thread.
|
||||
// TODO: Find a better solution by forcing the destructor to run in the
|
||||
// main thread, e.g. with a custom deleter on shared_ptr construction?
|
||||
historic_tiles.remove_if([](const Tile::Ptr& tile) {
|
||||
return tile.unique();
|
||||
});
|
||||
}
|
||||
|
||||
bool Map::render() {
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include <llmr/renderer/fill_bucket.hpp>
|
||||
#include <llmr/renderer/line_bucket.hpp>
|
||||
#include <llmr/style/style.hpp>
|
||||
#include <llmr/platform/platform.hpp>
|
||||
#include <llmr/util/string.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace llmr;
|
||||
@@ -47,8 +50,6 @@ Tile::Tile(ID id, const Style& style)
|
||||
debugFontBuffer(std::make_shared<DebugFontBuffer>()),
|
||||
fillBuffer(std::make_shared<FillBuffer>()),
|
||||
lineBuffer(std::make_shared<LineBuffer>()),
|
||||
data(0),
|
||||
bytes(0),
|
||||
style(style) {
|
||||
|
||||
// Initialize tile debug coordinates
|
||||
@@ -58,24 +59,35 @@ Tile::Tile(ID id, const Style& style)
|
||||
}
|
||||
|
||||
Tile::~Tile() {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
|
||||
// fprintf(stderr, "[%p] deleting tile %d/%d/%d\n", this, id.z, id.x, id.y);
|
||||
if (this->data) {
|
||||
free(this->data);
|
||||
this->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string Tile::toString() const {
|
||||
return util::sprintf("[tile %d/%d/%d]", id.z, id.x, id.y);
|
||||
}
|
||||
|
||||
void Tile::request() {
|
||||
state = Tile::loading;
|
||||
|
||||
void Tile::setData(uint8_t *data, uint32_t bytes) {
|
||||
this->data = (uint8_t *)malloc(bytes);
|
||||
this->bytes = bytes;
|
||||
memcpy(this->data, data, bytes);
|
||||
// Create http request
|
||||
std::string url = util::sprintf("http://localhost:3333/gl/tiles/plain/%d-%d-%d.vector.pbf",
|
||||
id.z, id.x, id.y);
|
||||
|
||||
// Note: Somehow this feels slower than the change to request_http()
|
||||
std::shared_ptr<Tile> tile = shared_from_this();
|
||||
platform::request_http(url, [=](const platform::Response& res) {
|
||||
if (res.code == 200) {
|
||||
tile->data.assign(res.body, res.body + res.length);
|
||||
|
||||
platform::async([tile]() {
|
||||
tile->parse();
|
||||
}, []() {
|
||||
// TODO: Make sure this gets passed the correct map ID/pointer.
|
||||
platform::restart(NULL);
|
||||
});
|
||||
} else {
|
||||
fprintf(stderr, "tile loading failed\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Tile::cancel() {
|
||||
@@ -88,14 +100,14 @@ void Tile::cancel() {
|
||||
}
|
||||
|
||||
bool Tile::parse() {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
// std::lock_guard<std::mutex> lock(mtx);
|
||||
|
||||
if (state == obsolete) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
tile = VectorTile(pbf(data, bytes));
|
||||
tile = VectorTile(pbf((const uint8_t *)data.data(), data.size()));
|
||||
parseStyleLayers(style.layers);
|
||||
} catch (const std::exception& ex) {
|
||||
fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what());
|
||||
|
||||
@@ -6,6 +6,7 @@ using namespace llmr;
|
||||
|
||||
VectorTile::VectorTile() {}
|
||||
|
||||
|
||||
VectorTile::VectorTile(pbf tile) {
|
||||
while (tile.next()) {
|
||||
if (tile.tag == 3) { // layer
|
||||
|
||||
Reference in New Issue
Block a user