Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

fixes #67: cancel unnecessary tile fetches #76

Merged
merged 15 commits into from
Feb 28, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/llmr/map/tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <llmr/util/noncopyable.hpp>
#include <llmr/geometry/debug_font_buffer.hpp>
#include <llmr/geometry/vao.hpp>
#include <llmr/platform/platform.hpp>

#include <cstdint>
#include <forward_list>
Expand Down Expand Up @@ -43,7 +44,8 @@ class Tile : public std::enable_shared_from_this<Tile>,
enum state {
initial,
loading,
ready,
loaded,
parsed,
obsolete
};

Expand Down Expand Up @@ -92,8 +94,8 @@ class Tile : public std::enable_shared_from_this<Tile>,
private:
// Source data
std::string data;

const Style& style;
platform::Request req;
};

}
Expand Down
14 changes: 10 additions & 4 deletions include/llmr/platform/platform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,26 @@

namespace llmr {

class Tile;

namespace platform {

// Restarts painting. This could for example trigger the event loop of the controlling application.
void restart();

struct Request {
int16_t identifier = -1;
std::string original_url;
};

struct Response {
int16_t code = -1;
std::string body;
};

// Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread.
void request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback);
// Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. Returns a cancellable request.
Request request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback);

// Cancels an HTTP request.
void cancel_request_http(Request request);

// Returns a relative timestamp in seconds. This value must be monotonic.
double time();
Expand Down
53 changes: 31 additions & 22 deletions ios/MBXViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

#include <llmr/llmr.hpp>
#include <llmr/platform/platform.hpp>
#include <llmr/map/tile.hpp>

NSString *const MBXNeedsRenderNotification = @"MBXNeedsRenderNotification";
NSString *const MBXUpdateActivityNotification = @"MBXUpdateActivityNotification";

@interface MBXViewController () <UIGestureRecognizerDelegate>

@property (nonatomic) EAGLContext *context;
@property (nonatomic) NSUInteger activityCount;
@property (nonatomic) CGPoint center;
@property (nonatomic) CGFloat scale;
@property (nonatomic) CGFloat angle;
Expand Down Expand Up @@ -153,11 +153,10 @@ - (void)updateRender:(NSNotification *)notification

- (void)updateNetworkActivity:(NSNotification *)notification
{
NSInteger input = [[notification userInfo][@"count"] integerValue];

self.activityCount += input;

[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(self.activityCount > 0)];
[[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:([downloadTasks count] > 0)];
}];
}

- (void)updateRender
Expand Down Expand Up @@ -391,7 +390,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecogni

MBXMapView *mapView;
CADisplayLink *displayLink;
NSOperationQueue *queue;

namespace llmr
{
Expand All @@ -402,22 +400,15 @@ void restart()
[[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil];
}

void request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
Request request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
{
[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@1 forKey:@"count"]];

if (!queue)
queue = [NSOperationQueue new];

NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@(url.c_str())]];

[NSURLConnection sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil];

Response res;

if (error == nil)
if ( ! error && [response isKindOfClass:[NSHTTPURLResponse class]])
{
res.code = [(NSHTTPURLResponse *)response statusCode];
res.body = { (const char *)[data bytes], [data length] };
Expand All @@ -427,11 +418,29 @@ void request_http(std::string url, std::function<void(Response&)> background_fun

dispatch_async(dispatch_get_main_queue(), ^(void)
{
foreground_callback();
foreground_callback();
});
}];

[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@(-1) forKey:@"count"]];
[[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil];
[task resume];

[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil];

Request req;

req.identifier = task.taskIdentifier;
req.original_url = url;

return req;
}

void cancel_request_http(Request request)
{
[[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
{
for (NSURLSessionDownloadTask *task in downloadTasks)
if (task.taskIdentifier == request.identifier)
return [task cancel];
}];
}

Expand Down
2 changes: 1 addition & 1 deletion ios/llmr-app.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
'INFOPLIST_FILE': 'Info.plist',
'CLANG_CXX_LIBRARY': 'libc++',
'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
'IPHONEOS_DEPLOYMENT_TARGET':'6.0',
'IPHONEOS_DEPLOYMENT_TARGET':'7.0',
'TARGETED_DEVICE_FAMILY': '1,2',
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_ENABLE_OBJC_ARC': 'YES'
Expand Down
4 changes: 2 additions & 2 deletions llmr.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
'xcode_settings': {
'SDKROOT': 'macosx',
'SUPPORTED_PLATFORMS':['macosx'],
'MACOSX_DEPLOYMENT_TARGET':'10.8',
'MACOSX_DEPLOYMENT_TARGET':'10.9',
'PUBLIC_HEADERS_FOLDER_PATH': 'include',
'OTHER_CPLUSPLUSFLAGS':[
'<@(png_cflags)'
Expand Down Expand Up @@ -140,7 +140,7 @@
'ARCHS': [ "armv7", "armv7s", "arm64", "i386" ],
'TARGETED_DEVICE_FAMILY': '1,2',
'CODE_SIGN_IDENTITY': 'iPhone Developer',
'IPHONEOS_DEPLOYMENT_TARGET': '5.0',
'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
'PUBLIC_HEADERS_FOLDER_PATH': 'include',
'GCC_INPUT_FILETYPE':'sourcecode.cpp.cpp',
'OTHER_CPLUSPLUSFLAGS':[
Expand Down
2 changes: 1 addition & 1 deletion macosx/llmr-app.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
'INFOPLIST_FILE': 'Info.plist',
'CLANG_CXX_LIBRARY': 'libc++',
'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
'MACOSX_DEPLOYMENT_TARGET':'10.8',
'MACOSX_DEPLOYMENT_TARGET':'10.9',
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_ENABLE_OBJC_ARC': 'YES'
},
Expand Down
47 changes: 30 additions & 17 deletions macosx/main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#include <llmr/platform/platform.hpp>
#include <llmr/map/tile.hpp>
#include "settings.hpp"

#include <cstdio>
Expand Down Expand Up @@ -239,33 +240,45 @@ void restart() {
[[NSApplication sharedApplication] postEvent: [NSEvent eventWithCGEvent:event] atStart:NO];
}

void request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback) {
if (!queue) {
queue = [NSOperationQueue new];
}

NSMutableURLRequest *urlRequest = [NSMutableURLRequest
requestWithURL:[NSURL
URLWithString:@(url.c_str())]];

[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue mainQueue]
completionHandler: ^(NSURLResponse * response, NSData * data, NSError * error) {
Request request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
{
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
Response res;
if (error == nil) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
res.code = [httpResponse statusCode];

if ( ! error && [response isKindOfClass:[NSHTTPURLResponse class]])
{
res.code = [(NSHTTPURLResponse *)response statusCode];
res.body = { (const char *)[data bytes], [data length] };
}

background_function(res);
dispatch_async(dispatch_get_main_queue(), ^(void) {

dispatch_async(dispatch_get_main_queue(), ^(void)
{
foreground_callback();
});
}];

[task resume];

Request req;

req.identifier = task.taskIdentifier;
req.original_url = url;

return req;
}

void cancel_request_http(Request request)
{
[[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
{
for (NSURLSessionDownloadTask *task in downloadTasks)
if (task.taskIdentifier == request.identifier)
return [task cancel];
}];
}

double time() {
return glfwGetTime();
Expand Down
8 changes: 4 additions & 4 deletions src/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ bool Map::findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::f
auto ids = Tile::children(id, z + 1);
for (const Tile::ID& child_id : ids) {
const Tile::Ptr& tile = hasTile(child_id);
if (tile && tile->state == Tile::ready) {
if (tile && tile->state == Tile::parsed) {
assert(tile);
retain.emplace_front(tile->id);
} else {
Expand All @@ -305,7 +305,7 @@ bool Map::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::for
for (int32_t z = id.z - 1; z >= minCoveringZoom; --z) {
const Tile::ID parent_id = Tile::parent(id, z);
const Tile::Ptr tile = hasTile(parent_id);
if (tile && tile->state == Tile::ready) {
if (tile && tile->state == Tile::parsed) {
assert(tile);
retain.emplace_front(tile->id);
return true;
Expand Down Expand Up @@ -361,7 +361,7 @@ bool Map::updateTiles() {
Tile::Ptr tile = addTile(id);
assert(tile);

if (tile->state != Tile::ready) {
if (tile->state != Tile::parsed) {
// The tile we require is not yet loaded. Try to find a parent or
// child tile that we already have.

Expand Down Expand Up @@ -416,7 +416,7 @@ bool Map::render() {

for (Tile::Ptr& tile : tiles) {
assert(tile);
if (tile->state == Tile::ready) {
if (tile->state == Tile::parsed) {
painter.changeMatrix(tile->id);
painter.render(tile);
}
Expand Down
14 changes: 8 additions & 6 deletions src/map/tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <llmr/renderer/fill_bucket.hpp>
#include <llmr/renderer/line_bucket.hpp>
#include <llmr/renderer/point_bucket.hpp>
#include <llmr/platform/platform.hpp>
#include <llmr/util/pbf.hpp>
#include <llmr/util/string.hpp>

Expand Down Expand Up @@ -75,22 +74,25 @@ void Tile::request() {

// Note: Somehow this feels slower than the change to request_http()
std::shared_ptr<Tile> tile = shared_from_this();
platform::request_http(url, [=](platform::Response& res) {
if (res.code == 200) {
platform::Request request = platform::request_http(url, [=](platform::Response& res) {
if (res.code == 200 && tile->state != obsolete) {
tile->state = Tile::loaded;
tile->data.swap(res.body);
tile->parse();
} else {
} else if (tile->state != obsolete) {
fprintf(stderr, "tile loading failed\n");
}
}, []() {
platform::restart();
});
req = request;
}

void Tile::cancel() {
// TODO: thread safety
if (state != obsolete) {
state = obsolete;
platform::cancel_request_http(req);
} else {
assert((!"logic error? multiple cancelleations"));
}
Expand All @@ -99,7 +101,7 @@ void Tile::cancel() {
bool Tile::parse() {
// std::lock_guard<std::mutex> lock(mtx);

if (state == obsolete) {
if (state != loaded) {
return false;
}

Expand All @@ -115,7 +117,7 @@ bool Tile::parse() {
if (state == obsolete) {
return false;
} else {
state = ready;
state = parsed;
}

return true;
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/painter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ void Painter::clear() {
}

void Painter::render(const Tile::Ptr& tile) {
if (tile->state != Tile::ready) {
if (tile->state != Tile::parsed) {
return;
}

Expand Down