Merge branch 'master' of github.com:mapbox/mapbox-gl-native

This commit is contained in:
Konstantin Käfer
2014-07-11 16:34:18 -07:00
121 changed files with 1418 additions and 1154 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
*.xcodeproj
*.o
*.actual.png
*.diff.png
/node_modules
/mapnik-packaging
/macosx/build

View File

@@ -14,6 +14,7 @@ env:
global:
- secure: "bG4YYWMfl9API0MSRgmOaJrlGLv06tRg9KJNawBieZvBJbITPpxVGJZT3/l/SEJ+Rl15e2dRex4k+MGQlmT2SqPQxTEYWv1qxNigKPPcla7IWeNmWWqW8uVvFjdglojgBOK2k/xErVQtA4zDfi3mwSXH4DKwquXWsoEKmX2SV7M="
- secure: "Cbvap9ubVKgjPe3hUhI6JGeDZzBXHpOG9RaYKh+SdoIPhKnlJiNOYm1egomi+e4uqJInlFKuVHTw7Ng9Cun6Zm0jIxpkSchv1GpsR7hmB3UGnGed19Dw8121FwuUaktN+4YnbVlsyd+u8EHD3+h58t4eELrLrZolM4rS7DL6caA="
- secure: "RiBIBfVhhaMjU5ksuwJO3shdvG9FpinBjdSv4co9jg9171SR8edNriedHjVKSIeBhSGNmZmX+twS3dJS/By6tl/LKh9sTynA+ZAYYljkE7jn881B/gMrlYvdAA6og5KvkhV1/0iJWlhuZrMTkhpDR200iLgg3EWBhWjltzmDW/I="
before_install:
- ./scripts/setup_travis.sh
@@ -29,6 +30,7 @@ script:
- make linux -j4 BUILDTYPE=${BUILDTYPE}
- make test -j4 BUILDTYPE=${BUILDTYPE}
- ./scripts/run_tests.sh
- ./scripts/compare_images.js
after_script:
- ./scripts/deploy_results.sh
@@ -38,7 +40,7 @@ notifications:
rooms:
secure: "SgMjGDp8MP+UTAY/aWJwSQH2hv1Q0vhEc1BdIde59+lEL3u6gNMSexUTSJoVxRlIQTFXDJBU7v58ISdgJX8cPa+UvIC8hhLsayM+cbm+J3jgy7V9E9wllq3RpmXN33TxY7nwKgWdIms2t9YKZco3y4dKKAUyHXrtMvw8NNPQM+4="
template:
- 'Build <a href="%{build_url}">#%{build_number}</a>: %{author} tested <a href="%{compare_url}">%{commit}</a> in branch <a href="https://github.com/%{repository_slug}/tree/%{branch}">%{branch}</a> of <a href="https://github.com/%{repository_slug}">%{repository_name}</a>: <b>%{commit_message}</b><br>%{message} (%{duration})'
- 'Build <a href="%{build_url}">#%{build_number}</a>: %{author} tested <a href="%{compare_url}">%{commit}</a> in branch <a href="https://github.com/%{repository_slug}/tree/%{branch}">%{branch}</a> of <a href="https://github.com/%{repository_slug}">%{repository_name}</a>: <b>%{commit_message}</b><br>%{message} (%{duration}) - Compare: <a href="http://mapbox-gl-testing.s3.amazonaws.com/headless/%{build_number}.1/index.html">1</a> <a href="http://mapbox-gl-testing.s3.amazonaws.com/headless/%{build_number}.2/index.html">2</a> <a href="http://mapbox-gl-testing.s3.amazonaws.com/headless/%{build_number}.3/index.html">3</a> <a href="http://mapbox-gl-testing.s3.amazonaws.com/headless/%{build_number}.4/index.html">4</a>'
format: html
git:

View File

@@ -25,11 +25,11 @@ build/test/Makefile: src common config.gypi test/test.gyp
deps/run_gyp test/test.gyp --depth=. -Goutput_dir=.. --generator-output=./build/test -f make
test: build/test/Makefile
$(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) test
$(MAKE) -C build/test BUILDTYPE=Testing V=$(V) test
test/%: build/test/Makefile
$(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) $*
(cd build/$(BUILDTYPE) && exec ./test_$*)
$(MAKE) -C build/test BUILDTYPE=Testing V=$(V) $*
(cd build/Testing && exec ./test_$*)
# build Mac OS X project for Xcode
xtest: config.gypi clear_xcode_cache node
@@ -42,7 +42,7 @@ xtest: config.gypi clear_xcode_cache node
# Builds the linux app with make. This is also used by Travis CI
linux: config.gypi linux/llmr-app.gyp node
deps/run_gyp linux/llmr-app.gyp --depth=. -Goutput_dir=.. --generator-output=./build/linux -f make
$(MAKE) -C build/linux BUILDTYPE=$(BUILDTYPE) V=$(V) linuxapp
$(MAKE) -C build/linux BUILDTYPE=Testing V=$(V) linuxapp
# Executes the Linux binary
run-linux: linux
@@ -78,9 +78,9 @@ xproj: config.gypi macosx/llmr-app.gyp clear_xcode_cache node
open ./build/macosx/llmr-app.xcodeproj
# build iOS project for Xcode
iproj: config.gypi ios/llmr-app.gyp clear_xcode_cache node
deps/run_gyp ios/llmr-app.gyp --depth=. --generator-output=./build -f xcode
open ./build/ios/llmr-app.xcodeproj
iproj: config.gypi ios/mapbox-gl-cocoa/app/llmr-app.gyp clear_xcode_cache node
deps/run_gyp ios/mapbox-gl-cocoa/app/llmr-app.gyp --depth=. --generator-output=./build -f xcode
open ./build/ios/mapbox-gl-cocoa/app/llmr-app.xcodeproj
# build Linux project for Xcode (Runs on Mac OS X too, but without platform-specific code)
lproj: config.gypi linux/llmr-app.gyp clear_xcode_cache node

View File

@@ -27,9 +27,18 @@ First off: if you hit problems during development try:
This will clear cached build data and update to the latest versions of dependencies.
### Mapbox API access tokens
The demo applications use Mapbox vector tiles, which **require a Mapbox account and API access token**. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/).
## OS X
First run:
in the Xcode project, click on the Target icon next to the Run/Stop button, and then "Edit Scheme". In the screen, add an environment variable with the name `MAPBOX_ACCESS_TOKEN` to the targets you want to run.
![Setting the access token](https://cloud.githubusercontent.com/assets/52399/3543326/9e7cfbb8-0860-11e4-8def-3684a9028b61.png)
Run:
make setup
@@ -52,6 +61,8 @@ First, pull down the submodule(s):
git submodule init
git submodule update
Insert your access token into `MBXViewController.h`.
Then run:
make setup
@@ -64,6 +75,8 @@ Target devices: iPhone 4 and above (4S, 5, 5c, 5s) and iPad 2 and above (3, 4, m
## Ubuntu
Set the environment variable `MAPBOX_ACCESS_TOKEN` to your token.
Ensure you have git and other build essentials:
sudo apt-get update

File diff suppressed because it is too large Load Diff

View File

@@ -33,6 +33,16 @@
'DEAD_CODE_STRIPPING': 'YES',
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES'
}
},
'Testing': {
'cflags_cc': [ '-O3' ],
'defines': [ 'NDEBUG', 'TESTING' ],
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '3',
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO',
'DEAD_CODE_STRIPPING': 'YES',
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES'
}
}
}
}

21
common/nslog_log.hpp Normal file
View File

@@ -0,0 +1,21 @@
#ifndef LLMR_COMMON_NSLOG_LOG
#define LLMR_COMMON_NSLOG_LOG
#include <llmr/platform/log.hpp>
namespace llmr {
class NSLogBackend : public LogBackend {
public:
inline ~NSLogBackend() = default;
void record(EventSeverity severity, Event event, const std::string &msg);
void record(EventSeverity severity, Event event, const char* format, ...);
void record(EventSeverity severity, Event event, int64_t code);
void record(EventSeverity severity, Event event, int64_t code, const std::string &msg);
};
}
#endif

37
common/nslog_log.mm Normal file
View File

@@ -0,0 +1,37 @@
#include "nslog_log.hpp"
#import <Foundation/Foundation.h>
namespace llmr {
void NSLogBackend::record(EventSeverity severity, Event event, const std::string &msg) {
NSLog(@"[%s] %s: %@", stringifyEventSeverity(severity), stringifyEvent(event),
[[NSString alloc] initWithBytes:msg.data()
length:msg.size()
encoding:NSUTF8StringEncoding]);
}
void NSLogBackend::record(EventSeverity severity, Event event, const char* format, ...) {
va_list args;
va_start(args, format);
const int len = vsnprintf(NULL, 0, format, args);
va_end(args);
std::unique_ptr<char[]> buffer(new char[len + 1]);
va_start(args, format);
vsnprintf(buffer.get(), len + 1, format, args);
va_end(args);
NSLog(@"[%s] %s: %s", stringifyEventSeverity(severity), stringifyEvent(event), buffer.get());
}
void NSLogBackend::record(EventSeverity severity, Event event, int64_t code) {
NSLog(@"[%s] %s: (%lld)", stringifyEventSeverity(severity), stringifyEvent(event), code);
}
void NSLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) {
NSLog(@"[%s] %s: (%lld) %@", stringifyEventSeverity(severity), stringifyEvent(event), code,
[[NSString alloc] initWithBytes:msg.data()
length:msg.size()
encoding:NSUTF8StringEncoding]);
}
}

29
common/stderr_log.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include "stderr_log.hpp"
#include <iostream>
namespace llmr {
void StderrLogBackend::record(EventSeverity severity, Event event, const std::string &msg) {
std::cerr << "[" << severity << "] " << event << ": " << msg << std::endl;
}
void StderrLogBackend::record(EventSeverity severity, Event event, const char* format, ...) {
std::cerr << "[" << severity << "] " << event << ": ";
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
std::cerr << std::endl;
}
void StderrLogBackend::record(EventSeverity severity, Event event, int64_t code) {
std::cerr << "[" << severity << "] " << event << ": (" << code << ")" << std::endl;
}
void StderrLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) {
std::cerr << "[" << severity << "] " << event << ": (" << code << ") " << msg << std::endl;
}
}

21
common/stderr_log.hpp Normal file
View File

@@ -0,0 +1,21 @@
#ifndef LLMR_COMMON_STDERR_LOG
#define LLMR_COMMON_STDERR_LOG
#include <llmr/platform/log.hpp>
namespace llmr {
class StderrLogBackend : public LogBackend {
public:
inline ~StderrLogBackend() = default;
void record(EventSeverity severity, Event event, const std::string &msg);
void record(EventSeverity severity, Event event, const char* format, ...);
void record(EventSeverity severity, Event event, int64_t code);
void record(EventSeverity severity, Event event, int64_t code, const std::string &msg);
};
}
#endif

View File

@@ -55,10 +55,11 @@ public:
void setAppliedClasses(const std::vector<std::string> &classes);
void toggleClass(const std::string &name);
const std::vector<std::string> &getAppliedClasses() const;
void setAppliedClasses(std::vector<std::string> &class_names);
void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0);
void setStyleJSON(std::string newStyleJSON);
std::string getStyleJSON() const;
void setAccessToken(std::string access_token);
std::string getAccessToken() const;
// Transition
void cancelTransitions();
@@ -166,6 +167,7 @@ private:
Painter painter;
std::string styleJSON = "";
std::string accessToken = "";
bool debug = false;
timestamp animationTime = 0;

View File

@@ -23,7 +23,8 @@ class Texturepool;
class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
public:
Source(SourceType type = SourceType::Vector, const std::string &url = "",
uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22);
uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22,
const std::string &access_token = "");
bool update(Map &map);
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
@@ -35,7 +36,7 @@ public:
std::forward_list<Tile::ID> getIDs() const;
void updateClipIDs(const std::map<Tile::ID, ClipID> &mapping);
static std::string normalizeSourceURL(const std::string &url);
static std::string normalizeSourceURL(const std::string &url, const std::string &access_token);
public:
const SourceType type;

View File

@@ -0,0 +1,63 @@
#ifndef LLMR_PLATFORM_EVENT
#define LLMR_PLATFORM_EVENT
#include <cstdint>
#include <ostream>
namespace llmr {
enum class EventSeverity : uint8_t {
Debug,
Info,
Test,
Warning,
Error,
};
EventSeverity parseEventSeverity(const char *name);
const char *stringifyEventSeverity(EventSeverity eventSeverity);
::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity);
enum class Event : uint8_t {
General,
Setup,
Shader,
ParseStyle,
ParseTile,
Render,
HttpRequest,
};
Event parseEvent(const char *name);
const char *stringifyEvent(Event event);
::std::ostream& operator<<(::std::ostream& os, Event event);
struct EventPermutation {
const EventSeverity severity;
const Event event;
constexpr bool operator==(const EventPermutation &rhs) const {
return severity == rhs.severity && event == rhs.event;
}
};
constexpr EventSeverity disabledEventSeverities[] = {
#if !DEBUG
EventSeverity::Debug,
#endif
#if !TESTING
EventSeverity::Test,
#endif
};
constexpr Event disabledEvents[] = {
};
constexpr EventPermutation disabledEventPermutations[] = {
{ EventSeverity::Debug, Event::Shader }
};
}
#endif

View File

@@ -0,0 +1,71 @@
#ifndef LLMR_PLATFORM_LOG
#define LLMR_PLATFORM_LOG
#include "event.hpp"
#include <memory>
#include <string>
namespace llmr {
class LogBackend {
public:
virtual inline ~LogBackend() = default;
virtual void record(EventSeverity severity, Event event, const std::string &msg) = 0;
virtual void record(EventSeverity severity, Event event, const char* format, ...) = 0;
virtual void record(EventSeverity severity, Event event, int64_t code) = 0;
virtual void record(EventSeverity severity, Event event, int64_t code, const std::string &msg) = 0;
};
class Log {
private:
template <typename T>
constexpr static bool includes(const T e, T const *l, const size_t i = 0) {
return i >= sizeof l ? false : *(l + i) == e ? true : includes(e, l, i + 1);
}
public:
template <typename ...Args>
static inline void Debug(Event event, Args&& ...args) {
Record(EventSeverity::Debug, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
static inline void Info(Event event, Args&& ...args) {
Record(EventSeverity::Info, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
static inline void Warning(Event event, Args&& ...args) {
Record(EventSeverity::Warning, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
static inline void Error(Event event, Args&& ...args) {
Record(EventSeverity::Error, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
static inline void Record(EventSeverity severity, Event event, Args&& ...args) {
if (!includes(severity, disabledEventSeverities) &&
!includes(event, disabledEvents) &&
!includes({ severity, event }, disabledEventPermutations)) {
if (Backend) {
Backend->record(severity, event, ::std::forward<Args>(args)...);
}
}
}
template<typename T, typename ...Args>
static inline const T &Set(Args&& ...args) {
Backend = ::std::unique_ptr<T>(new T(::std::forward<Args>(args)...));
return *dynamic_cast<T *>(Backend.get());
}
private:
static std::unique_ptr<LogBackend> Backend;
};
}
#endif

View File

@@ -85,7 +85,7 @@ public:
enum class GeometryType : uint8_t {
Any,
Point,
Line,
LineString,
Polygon
};

View File

@@ -29,14 +29,14 @@ private:
template <typename T>
struct ExponentialFunction {
inline ExponentialFunction(const T &value, float z_base, float slope, const T &min,
inline ExponentialFunction(const T &value, float z_base, float exp_base, float slope, const T &min,
const T &max)
: value(value), min(min), max(max), z_base(z_base), slope(slope) {}
: value(value), min(min), max(max), z_base(z_base), exp_base(exp_base), slope(slope) {}
T evaluate(float z) const;
private:
const T value, min, max;
const float z_base, slope;
const float z_base, exp_base, slope;
};
template <typename T>

View File

@@ -4,7 +4,6 @@
namespace llmr {
enum class PropertyKey {
FillEnabled,
FillAntialias,
FillOpacity,
FillColor,
@@ -15,7 +14,6 @@ enum class PropertyKey {
FillTranslateAnchor,
FillImage,
LineEnabled,
LineOpacity,
LineColor,
LineTranslate, // for transitions only
@@ -30,12 +28,10 @@ enum class PropertyKey {
LineDashGap,
LineImage,
IconEnabled,
IconOpacity,
IconRotate,
IconRotateAnchor,
TextEnabled,
TextOpacity,
TextSize,
TextColor,
@@ -43,10 +39,8 @@ enum class PropertyKey {
TextHaloWidth,
TextHaloBlur,
CompositeEnabled,
CompositeOpacity,
RasterEnabled,
RasterOpacity,
RasterSpin,
RasterBrightnessLow,

View File

@@ -16,6 +16,7 @@
namespace llmr {
class Map;
class Sprite;
class Source;
class StyleLayer;
@@ -27,7 +28,7 @@ public:
struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} };
public:
Style();
Style(Map &map);
void loadJSON(const uint8_t *const data);
@@ -63,6 +64,7 @@ private:
private:
Map &map;
std::set<std::shared_ptr<Source>> activeSources;
PropertyTransition defaultTransition;
bool initial_render_complete = false;

View File

@@ -71,7 +71,8 @@ class StyleBucket {
public:
typedef std::shared_ptr<StyleBucket> Ptr;
BucketType type = BucketType::None;
StyleBucket(StyleLayerType type);
std::string name;
std::shared_ptr<Source> source;
std::string source_layer;

View File

@@ -61,6 +61,8 @@ public:
// The name of this layer.
const std::string id;
StyleLayerType type = StyleLayerType::Unknown;
// Bucket information, telling the renderer how to generate the geometries
// for this layer (feature property filters, tessellation instructions, ...).
std::shared_ptr<StyleBucket> bucket;

View File

@@ -17,6 +17,7 @@ namespace llmr {
enum class ClassID : uint32_t;
class Map;
class StyleLayer;
class StyleLayerGroup;
@@ -24,6 +25,8 @@ class StyleParser {
public:
using JSVal = const rapidjson::Value&;
StyleParser(Map &map);
void parse(JSVal document);
std::shared_ptr<StyleLayerGroup> getLayers() {
@@ -92,6 +95,8 @@ private:
std::forward_list<Value> parseValues(JSVal values);
private:
Map &map;
std::unordered_map<std::string, const rapidjson::Value *> constants;
std::unordered_map<std::string, const std::shared_ptr<Source>> sources;

View File

@@ -14,7 +14,6 @@ namespace llmr {
struct FillProperties {
FillProperties() {}
bool enabled = true;
bool antialias = true;
float opacity = 1.0f;
Color fill_color = {{ 0, 0, 0, 1 }};
@@ -24,13 +23,12 @@ struct FillProperties {
std::string image;
inline bool isVisible() const {
return enabled && opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0);
return opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0);
}
};
struct LineProperties {
inline LineProperties() {}
bool enabled = true;
float opacity = 1.0f;
Color color = {{ 0, 0, 0, 1 }};
std::array<float, 2> translate = {{ 0, 0 }};
@@ -42,25 +40,23 @@ struct LineProperties {
std::string image;
inline bool isVisible() const {
return enabled && opacity > 0 && color[3] > 0 && width > 0;
return opacity > 0 && color[3] > 0 && width > 0;
}
};
struct IconProperties {
inline IconProperties() {}
bool enabled = true;
float opacity = 1.0f;
float rotate = 0.0f;
RotateAnchorType rotate_anchor = RotateAnchorType::Default;
inline bool isVisible() const {
return enabled && opacity > 0;
return opacity > 0;
}
};
struct TextProperties {
inline TextProperties() {}
bool enabled = true;
float opacity = 1.0f;
float size = 12.0f;
Color color = {{ 0, 0, 0, 1 }};
@@ -69,23 +65,21 @@ struct TextProperties {
float halo_blur = 1.0f;
inline bool isVisible() const {
return enabled && opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0;
return opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0;
}
};
struct CompositeProperties {
inline CompositeProperties() {}
bool enabled = true;
float opacity = 1.0f;
inline bool isVisible() const {
return enabled && opacity > 0;
return opacity > 0;
}
};
struct RasterProperties {
inline RasterProperties() {}
bool enabled = true;
float opacity = 1.0f;
float spin = 0.0f;
std::array<float, 2> brightness = {{ 0, 1 }};
@@ -94,7 +88,7 @@ struct RasterProperties {
float fade = 0.0f;
inline bool isVisible() const {
return enabled && opacity > 0;
return opacity > 0;
}
};

View File

@@ -9,19 +9,20 @@ namespace llmr {
// Stores a premultiplied color, with all four channels ranging from 0..1
typedef std::array<float, 4> Color;
enum class BucketType : uint8_t {
None,
enum class StyleLayerType : uint8_t {
Unknown,
Fill,
Line,
Icon,
Text,
Raster,
Default = None
Composite,
Background
};
BucketType parseBucketType(const std::string &type);
const char *stringifyBucketType(BucketType type);
std::ostream& operator<<(std::ostream&, BucketType type);
StyleLayerType parseStyleLayerType(const std::string &type);
const char *stringifyStyleLayerType(StyleLayerType type);
std::ostream& operator<<(std::ostream&, StyleLayerType type);
enum class WindingType : uint8_t {

View File

@@ -10,12 +10,6 @@ typedef util::variant<bool, int64_t, uint64_t, double, std::string> Value;
std::string toString(const Value &value);
inline std::string& operator+=(std::string& out, const Value& value) {
out += toString(value);
return out;
}
Value parseValue(pbf data);
namespace util {

View File

@@ -1,6 +1,8 @@
#ifndef LLMR_UTIL_TIMER
#define LLMR_UTIL_TIMER
#include <llmr/platform/event.hpp>
#include <string>
namespace llmr {
@@ -9,24 +11,29 @@ namespace util {
#ifndef DISABLE_TIMER
class timer {
public:
timer();
timer(const std::string &name);
timer(Event event = Event::General);
timer(EventSeverity severity, Event event = Event::General);
timer(const std::string &name, Event event = Event::General);
timer(const std::string &name, EventSeverity severity, Event event = Event::General);
void report(const std::string &name);
~timer();
private:
const std::string name;
EventSeverity severity = EventSeverity::Debug;
Event event = Event::General;
uint64_t start;
};
#else
class timer {
inline timer() {}
inline timer(const std::string &name) {}
inline void report (const std::string &name) {}
inline timer(Event event = Event::General);
inline timer(EventSeverity severity, Event event = Event::General);
inline timer(const std::string &name, Event event = Event::General);
inline timer(const std::string &name, EventSeverity severity, Event event = Event::General);
inline void report(const std::string &name) {}
inline ~timer() {}
};
#endif
}
}

View File

@@ -9,40 +9,43 @@ namespace regex_impl = boost;
namespace regex_impl = std;
#endif
#include <map>
namespace llmr {
namespace util {
namespace detail {
const regex_impl::regex tokenRegex("\\{\\{(\\w+)\\}\\}");
const regex_impl::regex tokenRegex("\\{(\\w+)\\}");
const regex_impl::sregex_token_iterator tokensEnd = regex_impl::sregex_token_iterator();
}
template <typename Tokens>
std::string replaceTokens(const std::string &source, const Tokens &tokens) {
template <typename Lookup>
std::string replaceTokens(const std::string &source, const Lookup &lookup) {
std::string result;
result.reserve(source.size());
bool token = false;
for (auto token_it = regex_impl::sregex_token_iterator(source.begin(), source.end(),
detail::tokenRegex, {-1, 1});
token_it != detail::tokensEnd; ++token_it, token = !token) {
token_it != detail::tokensEnd; ++token_it, token = !token) {
if (!token_it->matched) {
continue;
}
if (token) {
const auto it_prop = tokens.find(token_it->str());
if (it_prop != tokens.end()) {
result += it_prop->second;
}
} else {
result += token_it->str();
}
result += token ? lookup(token_it->str()) : token_it->str();
}
return result;
}
template <typename T>
inline std::string replaceTokens(const std::string &source, const std::map<std::string, T> &properties) {
return replaceTokens(source, [&properties](const std::string &token) -> std::string {
const auto it_prop = properties.find(token);
return it_prop != properties.end() ? toString(it_prop->second) : "";
});
}
} // end namespace util
} // end namespace llmr

View File

@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.mapbox.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.0.1</string>
<key>CFBundleSignature</key>
<string>LLMR</string>
<key>CFBundleVersion</key>
<string>0.0.1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSHumanReadableCopyright</key>
<string>(c) 2014 Mapbox</string>
</dict>
</plist>

View File

@@ -1,15 +0,0 @@
//
// MBXAppDelegate.h
// ios
//
// Created by Justin R. Miller on 1/27/14.
//
//
#import <UIKit/UIKit.h>
@interface MBXAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View File

@@ -1,24 +0,0 @@
//
// MBXAppDelegate.m
// ios
//
// Created by Justin R. Miller on 1/27/14.
//
//
#import "MBXAppDelegate.h"
#import "MBXViewController.h"
@implementation MBXAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [MBXViewController new];
[self.window makeKeyAndVisible];
return YES;
}
@end

View File

@@ -1,5 +0,0 @@
#import <UIKit/UIKit.h>
@interface MBXViewController : UIViewController
@end

View File

@@ -1,214 +0,0 @@
#import "MBXViewController.h"
#import "MGLMapView.h"
#import "../common/settings_nsuserdefaults.hpp"
#import <CoreLocation/CoreLocation.h>
@interface MBXViewController () <CLLocationManagerDelegate>
@property (nonatomic) MGLMapView *mapView;
@property (nonatomic) BOOL debug;
@property (nonatomic) UIView *palette;
@property (nonatomic) CLLocationManager *locationManager;
@end
@implementation MBXViewController
llmr::Settings_NSUserDefaults *settings = nullptr;
#pragma mark - Setup
- (id)init
{
self = [super init];
if (self)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveState:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restoreState:) name:UIApplicationWillEnterForegroundNotification object:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds];
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.mapView];
self.mapView.viewControllerForLayoutGuides = self;
settings = new llmr::Settings_NSUserDefaults();
[self restoreState:nil];
[self setupDebugUI];
self.locationManager = [CLLocationManager new];
self.locationManager.delegate = self;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
- (void)saveState:(NSNotification *)notification
{
if (self.mapView && settings)
{
settings->longitude = self.mapView.centerCoordinate.longitude;
settings->latitude = self.mapView.centerCoordinate.latitude;
settings->zoom = self.mapView.zoomLevel;
settings->angle = self.mapView.direction;
settings->debug = self.mapView.isDebugActive;
settings->save();
}
}
- (void)restoreState:(NSNotification *)notification
{
if (self.mapView && settings) {
settings->load();
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(settings->latitude, settings->longitude) zoomLevel:settings->zoom animated:NO];
self.mapView.direction = settings->angle;
[self.mapView setDebugActive:settings->debug];
}
}
#pragma clang diagnostic pop
- (void)setupDebugUI
{
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)];
singleTap.numberOfTapsRequired = 1;
[self.mapView addGestureRecognizer:singleTap];
NSArray *selectorNames = @[ @"unrotate", @"resetPosition", @"toggleDebug", @"toggleStyle", @"locateUser" ];
CGFloat buttonSize = 40;
CGFloat bufferSize = 20;
CGFloat alpha = 0.75;
CGFloat paletteWidth = buttonSize + (2 * bufferSize);
CGFloat paletteHeight = [selectorNames count] * (buttonSize + bufferSize) + bufferSize;
self.palette = [[UIView alloc] initWithFrame:CGRectMake(self.view.bounds.size.width - paletteWidth,
(self.view.bounds.size.height - paletteHeight) / 2,
paletteWidth,
paletteHeight)];
self.palette.backgroundColor = [UIColor colorWithWhite:0 alpha:alpha];
self.palette.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
self.palette.layer.cornerRadius = bufferSize;
[self.view addSubview:self.palette];
for (NSString *selectorName in selectorNames)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(bufferSize,
([selectorNames indexOfObject:selectorName] * (buttonSize + bufferSize)) + bufferSize,
buttonSize,
buttonSize);
[button setImage:[UIImage imageNamed:[selectorName stringByAppendingString:@".png"]] forState:UIControlStateNormal];
[button addTarget:self action:NSSelectorFromString(selectorName) forControlEvents:UIControlEventTouchUpInside];
[self.palette addSubview:button];
}
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
#pragma mark - Debugging UI
- (void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap
{
if (singleTap.state == UIGestureRecognizerStateEnded)
{
[self togglePalette];
}
}
- (void)togglePalette
{
if (self.palette.alpha < 1)
{
self.palette.userInteractionEnabled = YES;
[UIView animateWithDuration:0.25 animations:^(void)
{
self.palette.alpha = 1;
}];
}
else
{
self.palette.userInteractionEnabled = NO;
[UIView animateWithDuration:0.25 animations:^(void)
{
self.palette.alpha = 0;
}];
}
}
- (void)unrotate
{
[self.mapView resetNorth];
}
- (void)resetPosition
{
[self.mapView resetPosition];
}
- (void)toggleDebug
{
[self.mapView toggleDebug];
self.debug = ! self.debug;
}
- (void)toggleStyle
{
[self.mapView toggleStyle];
}
- (void)locateUser
{
[self.locationManager startUpdatingLocation];
}
#pragma mark - Destruction
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (settings)
{
[self saveState:nil];
delete settings;
settings = nullptr;
}
}
#pragma mark - User location
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *latestLocation = locations.lastObject;
if ([latestLocation distanceFromLocation:[[CLLocation alloc] initWithLatitude:self.mapView.centerCoordinate.latitude longitude:self.mapView.centerCoordinate.longitude]] > 100)
{
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(latestLocation.coordinate.latitude, latestLocation.coordinate.longitude) zoomLevel:17 animated:YES];
}
[self.locationManager stopUpdatingLocation];
}
#pragma clang diagnostic pop
@end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -1,70 +0,0 @@
{
'includes': [
'../common.gypi',
'../config.gypi'
],
'targets': [
{
"target_name": "iosapp",
"product_name": "Mapbox GL",
"type": "executable",
"sources": [
"./main.m",
"./MBXAppDelegate.h",
"./MBXAppDelegate.m",
"./MBXViewController.h",
"./MBXViewController.mm",
'<!@(find mapbox-gl-cocoa/mapbox-gl-cocoa -type f -name "*.h")',
'<!@(find mapbox-gl-cocoa/mapbox-gl-cocoa -type f -name "*.m")',
'<!@(find mapbox-gl-cocoa/mapbox-gl-cocoa -type f -name "*.mm")',
"../common/settings_nsuserdefaults.hpp",
"../common/settings_nsuserdefaults.mm",
"../common/foundation_request.h",
"../common/foundation_request.mm",
],
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'<!@(find img -type f)',
'<!@(find mapbox-gl-cocoa/mapbox-gl-cocoa/Resources -type f)',
'<(SHARED_INTERMEDIATE_DIR)/bin/style.min.js'
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
'$(SDKROOT)/System/Library/Frameworks/OpenGLES.framework',
'$(SDKROOT)/System/Library/Frameworks/GLKit.framework',
'$(SDKROOT)/System/Library/Frameworks/CoreLocation.framework',
'$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework'
],
},
'xcode_settings': {
'SDKROOT': 'iphoneos',
'SUPPORTED_PLATFORMS':['iphonesimulator','iphoneos'],
'ARCHS': [ "armv7", "armv7s", "arm64", "i386" ],
'INFOPLIST_FILE': 'Info.plist',
'CLANG_CXX_LIBRARY': 'libc++',
'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
'IPHONEOS_DEPLOYMENT_TARGET':'7.0',
'TARGETED_DEVICE_FAMILY': '1,2',
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_ENABLE_OBJC_ARC': 'YES'
},
'configurations': {
'Debug': {
'xcode_settings': {
'CODE_SIGN_IDENTITY': 'iPhone Developer',
}
},
'Release': {
'xcode_settings': {
'CODE_SIGN_IDENTITY': 'iPhone Distribution',
}
}
},
"dependencies": [
"../llmr.gyp:llmr-ios"
]
}
]
}

View File

@@ -1,18 +0,0 @@
//
// main.m
// ios
//
// Created by Justin R. Miller on 1/27/14.
//
//
#import <UIKit/UIKit.h>
#import "MBXAppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([MBXAppDelegate class]));
}
}

View File

@@ -15,6 +15,8 @@
'../common/glfw_view.hpp',
'../common/glfw_view.cpp',
'../common/curl_request.cpp',
'../common/stderr_log.hpp',
'../common/stderr_log.cpp',
],
'conditions': [

View File

@@ -8,6 +8,7 @@
#include "../common/settings_json.hpp"
#include "../common/glfw_view.hpp"
#include "../common/stderr_log.hpp"
GLFWView *view = nullptr;
@@ -22,6 +23,8 @@ void quit_handler(int) {
}
int main(int argc, char *argv[]) {
llmr::Log::Set<llmr::StderrLogBackend>();
int fullscreen_flag = 0;
const struct option long_options[] = {
@@ -60,6 +63,14 @@ int main(int argc, char *argv[]) {
map.setAngle(settings.angle);
map.setDebug(settings.debug);
// Set access token if present
const char *token = getenv("MAPBOX_ACCESS_TOKEN");
if (token == nullptr) {
llmr::Log::Warning(llmr::Event::Setup, "no access token set. mapbox.com tiles won't work.");
} else {
map.setAccessToken(std::string(token));
}
// Load style
map.setStyleJSON(stylejson.str());

View File

@@ -1 +0,0 @@
Icon from http://dryicons.com/icon/architecture-blueprint-icons-set/map/

View File

@@ -16,6 +16,8 @@
'../common/glfw_view.cpp',
'../common/foundation_request.h',
'../common/foundation_request.mm',
'../common/nslog_log.hpp',
'../common/nslog_log.mm',
],
'product_extension': 'app',
'mac_bundle': 1,

View File

@@ -1,9 +1,12 @@
#include "../common/settings_nsuserdefaults.hpp"
#include "../common/glfw_view.hpp"
#include "../common/nslog_log.hpp"
#import <Foundation/Foundation.h>
int main() {
llmr::Log::Set<llmr::NSLogBackend>();
GLFWView view;
llmr::Map map(view);
@@ -13,6 +16,14 @@ int main() {
map.setAngle(settings.angle);
map.setDebug(settings.debug);
// Set access token if present
const char *token = getenv("MAPBOX_ACCESS_TOKEN");
if (token == nullptr) {
llmr::Log::Warning(llmr::Event::Setup, "no access token set. mapbox.com tiles won't work.");
} else {
map.setAccessToken(std::string(token));
}
// Load style
NSString *path = [[NSBundle mainBundle] pathForResource:@"style.min" ofType:@"js"];
NSString *json = [NSString stringWithContentsOfFile:path
@@ -20,8 +31,6 @@ int main() {
error:nil];
map.setStyleJSON((std::string)[json cStringUsingEncoding:[NSString defaultCStringEncoding]]);
// fprintf(stderr, "lon: %f, lat: %f, zoom: %f, angle: %f, debug: %d\n", settings.l)
int ret = view.run();
// Save settings

117
scripts/compare_images.js Executable file
View File

@@ -0,0 +1,117 @@
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var base_dir = path.join(path.resolve('.'), 'test/fixtures/styles');
var files = fs.readdirSync(base_dir).filter(function(name) {
return name.match(/\.info\.json$/);
});
var html =
'<style>\n' +
' body { font-family: Helvetica; }\n' +
' h2 a { color:white; text-decoration:none; }\n' +
'</style>\n' +
'<table>\n' +
'<tr>\n' +
' <th>Actual</th>\n' +
' <th>Expected</th>\n' +
' <th>Info</th>\n' +
'</tr>\n';
var exitCode = 0;
var failures = 0;
processFiles();
function processFiles() {
if (!files.length) return done();
var name = files.shift();
var info = require(path.join(base_dir, name));
var keys = Object.keys(info);
processFileTest();
function processFileTest() {
if (!keys.length) return processFiles();
var key = keys.shift();
var base = path.basename(name, '.info.json');
var actual = path.join(base_dir, base + '/' + key + '.actual.png');
var expected = path.join(base_dir, base + '/' + key + '.expected.png');
var diff = path.join(base_dir, base + '/' + key + '.diff.png');
var compare = spawn('compare', ['-metric', 'MAE', actual, expected, diff ]);
var error = '';
compare.stderr.on('data', function(data) {
error += data.toString();
});
compare.on('exit', function(code, signal) {
// The compare program returns 2 on error otherwise 0 if the images are similar or 1 if they are dissimilar.
if (code == 2) {
writeResult(base, key, info[key], error.trim(), Infinity);
exitCode = 2;
} else {
var match = error.match(/^\d+(?:\.\d+)?\s+\(([^\)]+)\)\s*$/);
var difference = match ? parseFloat(match[1]) : Infinity;
writeResult(base, key, info[key], match ? '' : error, difference);
}
processFileTest();
});
compare.stdin.end();
}
}
function writeResult(base, key, info, error, difference) {
var color = 'green';
var allowedDifference = ('diff' in info) ? info.diff : 0.01;
if (difference > allowedDifference) {
color = 'red';
if (exitCode < 1) {
exitCode = 1;
}
failures++;
}
html +=
'<tr>\n' +
' <td><img src="' + base + '/' + key + '.actual.png" onmouseover="this.src=\'' + base + '/' + key + '.expected.png\'" onmouseout="this.src=\'' + base + '/' + key + '.actual.png\'"></td>\n' +
' <td><img src="' + base + '/' + key + '.expected.png" onmouseover="this.src=\'' + base + '/' + key + '.diff.png\'" onmouseout="this.src=\'' + base + '/' + key + '.expected.png\'"></td>\n' +
' <td>\n' +
' <h2 style="text-align:center; background:' + color + '"><a href="' + base + '.style.json">' + base + '/' + key + '</a></h2>\n' +
(error ? ' <p>' + error + '</p>\n' : '') +
' <ul>\n' +
' <li>diff: <strong>' + difference + '</strong></li>\n' +
' <li>zoom: <strong>' + (info.zoom || 0) + '</strong></li>\n' +
' <li>center: <strong>' + (info.center || [0, 0]) + '</strong></li>\n' +
' <li>bearing: <strong>' + (info.bearing || 0) + '</strong></li>\n' +
' <li>width: <strong>' + (info.width || 512) + '</strong></li>\n' +
' <li>height: <strong>' + (info.height || 512) + '</strong></li>\n' +
' </ul>\n' +
' </td>\n' +
'</tr>\n'
;
}
function done() {
html += "</table>\n";
fs.writeFileSync(path.join(base_dir, 'index.html'), html);
console.warn('Results at: ' + path.join(base_dir, 'index.html'));
if (failures) {
console.warn('\x1B[1m\x1B[31m' + failures + ' ' + (failures == 1 ? 'image doesn\'t' : 'images don\'t') + ' match\x1B[39m\x1B[22m');
} else {
console.warn('\x1B[1m\x1B[32mAll images match\x1B[39m\x1B[22m');
}
process.exit(exitCode);
}

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var html =
'<style>body { font-family: Helvetica; }</style>\n' +
'<table>\n' +
'<tr>\n' +
' <th>Actual</th>\n' +
' <th>Expected</th>\n' +
' <th>Info</th>\n' +
'</tr>\n';
var dir = fs.readdirSync('./test/fixtures/styles').filter(function(name) {
return name.match(/\.info\.json$/);
}).forEach(function(name) {
var info = require(path.join(path.resolve('.'), './test/fixtures/styles', name));
var base = path.basename(name, '.info.json');
html +=
'<tr>\n' +
' <td><img src="' + base + '.actual.png"></td>\n' +
' <td><img src="https://raw.githubusercontent.com/mapbox/mapbox-gl-native/' + process.env.TRAVIS_COMMIT + '/test/fixtures/styles/' + base + '.expected.png"></td>\n' +
' <td>\n' +
' <h2 style="text-align:center"><a href="https://raw.githubusercontent.com/mapbox/mapbox-gl-native/' + process.env.TRAVIS_COMMIT + '/test/fixtures/styles/' + base + '.style.json">' + base + '</a></h2>\n' +
' <ul>\n' +
' <li>zoom: <strong>' + (info.zoom || 0) + '</strong></li>\n' +
' <li>latitude: <strong>' + (info.latitude || 0) + '</strong></li>\n' +
' <li>longitude: <strong>' + (info.longitude || 0) + '</strong></li>\n' +
' <li>angle: <strong>' + (info.angle || 0) + '</strong></li>\n' +
' <li>width: <strong>' + (info.width || 0) + '</strong></li>\n' +
' <li>height: <strong>' + (info.height || 0) + '</strong></li>\n' +
' </ul>\n' +
' </td>\n' +
'</tr>\n'
;
});
html += "</table\n";
fs.writeFileSync('./test/fixtures/styles/index.html', html);

View File

@@ -3,9 +3,6 @@
set -e
set -o pipefail
node scripts/
aws s3 cp test/fixtures/styles/ s3://mapbox-gl-testing/headless/$TRAVIS_JOB_NUMBER/ --acl public-read --recursive
aws s3 cp test/fixtures/styles/ s3://mapbox-gl-testing/headless/$TRAVIS_BUILD_NUMBER/$TRAVIS_JOB_NUMBER/ --acl public-read --recursive --exclude "*" --include "*.actual.png" --include "*.html"
echo http://mapbox-gl-testing.s3.amazonaws.com/headless/$TRAVIS_BUILD_NUMBER/$TRAVIS_JOB_NUMBER/index.html
echo http://mapbox-gl-testing.s3.amazonaws.com/headless/$TRAVIS_JOB_NUMBER/index.html

View File

@@ -3,9 +3,7 @@
set -e
set -o pipefail
BUILDTYPE="${BUILDTYPE:-Release}"
cd build/${BUILDTYPE}
cd build/Testing
for TEST in ./test_* ; do
${TEST}

View File

@@ -22,7 +22,7 @@ using namespace llmr;
Map::Map(View& view)
: view(view),
transform(),
style(std::make_shared<Style>()),
style(std::make_shared<Style>(*this)),
glyphAtlas(std::make_shared<GlyphAtlas>(1024, 1024)),
spriteAtlas(std::make_shared<SpriteAtlas>(512, 512)),
texturepool(std::make_shared<Texturepool>()),
@@ -183,6 +183,14 @@ std::string Map::getStyleJSON() const {
return styleJSON;
}
void Map::setAccessToken( std::string access_token) {
accessToken.swap(access_token);
}
std::string Map::getAccessToken() const {
return accessToken;
}
#pragma mark - Size
// Note: This function is called from another thread. Make sure you only call threadsafe functions!
@@ -397,10 +405,6 @@ const std::vector<std::string> &Map::getAppliedClasses() const {
return style->getAppliedClasses();
}
void Map::setAppliedClasses(std::vector<std::string> &class_names) {
style->setAppliedClasses(class_names);
}
void Map::setDefaultTransitionDuration(uint64_t duration_milliseconds) {
style->setDefaultTransitionDuration(duration_milliseconds);
}
@@ -600,23 +604,23 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
// Abort early if we can already deduce from the bucket type that
// we're not going to render anything anyway during this pass.
switch (layer_desc->bucket->type) {
case BucketType::Fill:
switch (layer_desc->type) {
case StyleLayerType::Fill:
if (!layer_desc->getProperties<FillProperties>().isVisible()) return;
break;
case BucketType::Line:
case StyleLayerType::Line:
if (pass == Opaque) return;
if (!layer_desc->getProperties<LineProperties>().isVisible()) return;
break;
case BucketType::Icon:
case StyleLayerType::Icon:
if (pass == Opaque) return;
if (!layer_desc->getProperties<IconProperties>().isVisible()) return;
break;
case BucketType::Text:
case StyleLayerType::Text:
if (pass == Opaque) return;
if (!layer_desc->getProperties<TextProperties>().isVisible()) return;
break;
case BucketType::Raster:
case StyleLayerType::Raster:
if (pass == Translucent) return;
if (!layer_desc->getProperties<RasterProperties>().isVisible()) return;
break;
@@ -626,7 +630,7 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
if (debug::renderTree) {
std::cout << std::string(indent * 4, ' ') << "- " << layer_desc->id << " ("
<< layer_desc->bucket->type << ")" << std::endl;
<< layer_desc->type << ")" << std::endl;
}
layer_desc->bucket->source->render(painter, layer_desc);

View File

@@ -7,6 +7,7 @@
#include <llmr/util/string.hpp>
#include <llmr/util/texturepool.hpp>
#include <llmr/util/vec.hpp>
#include <llmr/util/token.hpp>
#include <llmr/util/std.hpp>
#include <llmr/geometry/glyph_atlas.hpp>
#include <llmr/style/style_layer.hpp>
@@ -18,23 +19,26 @@
namespace llmr {
Source::Source(SourceType type, const std::string &url,
uint32_t tile_size, uint32_t min_zoom, uint32_t max_zoom)
uint32_t tile_size, uint32_t min_zoom, uint32_t max_zoom,
const std::string &access_token)
: type(type),
url(normalizeSourceURL(url)),
url(normalizeSourceURL(url, access_token)),
tile_size(tile_size),
min_zoom(min_zoom),
max_zoom(max_zoom) {}
std::string Source::normalizeSourceURL(const std::string &url) {
std::string Source::normalizeSourceURL(const std::string &url, const std::string &access_token) {
const std::string t = "mapbox://";
if (url.compare(0, t.length(), t) == 0) {
return std::string("http://api.tiles.mapbox.com/v3/") + url.substr(t.length()) + "/%d/%d/%d.vector.pbf";
if (access_token.empty()) {
throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources");
}
return std::string("https://api.tiles.mapbox.com/v4/") + url.substr(t.length()) + "/{z}/{x}/{y}.vector.pbf?access_token=" + access_token;
} else {
return url;
}
}
bool Source::update(Map &map) {
if (map.getTime() > updated) {
return updateTiles(map);
@@ -142,14 +146,17 @@ TileData::State Source::addTile(Map &map, const Tile::ID& id) {
if (!new_tile.data) {
// If we don't find working tile data, we're just going to load it.
std::string formed_url;
const std::string formed_url = util::replaceTokens(url, [&](const std::string &token) -> std::string {
if (token == "z") return std::to_string(normalized_id.z);
if (token == "x") return std::to_string(normalized_id.x);
if (token == "y") return std::to_string(normalized_id.y);
if (token == "ratio") return (map.getState().getPixelRatio() > 1.0 ? "@2x" : "");
return "";
});
if (type == SourceType::Vector) {
formed_url = util::sprintf<256>(url, normalized_id.z, normalized_id.x, normalized_id.y);
new_tile.data = std::make_shared<VectorTileData>(normalized_id, map, formed_url);
} else if (type == SourceType::Raster) {
formed_url = util::sprintf<256>(url, normalized_id.z, normalized_id.x, normalized_id.y, (map.getState().getPixelRatio() > 1.0 ? "@2x" : ""));
new_tile.data = std::make_shared<RasterTileData>(normalized_id, map, formed_url);
} else {
throw std::runtime_error("source type not implemented");

View File

@@ -122,7 +122,7 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu
} else if (bucket_desc->render.is<StyleBucketRaster>()) {
return nullptr;
} else {
fprintf(stderr, "[WARNING] unknown bucket render type for layer '%s'\n", bucket_desc->source_layer.c_str());
fprintf(stderr, "[WARNING] unknown bucket render type for layer '%s' (source layer '%s')\n", bucket_desc->name.c_str(), bucket_desc->source_layer.c_str());
}
} else {
// The layer specified in the bucket does not exist. Do nothing.

View File

@@ -92,7 +92,7 @@ float TransformState::getPixelRatio() const {
#pragma mark - Zoom
float TransformState::getNormalizedZoom() const {
return std::log(scale * util::tileSize / 256.0f) / M_LN2;
return std::log(scale * util::tileSize / 512.0f) / M_LN2;
}
int32_t TransformState::getIntegerZoom() const {

View File

@@ -272,7 +272,7 @@ void FilteredVectorTileLayer::iterator::operator++() {
} else if (feature_pbf.tag == 3) { // geometry type
switch (FeatureType(feature_pbf.varint())) {
case FeatureType::Point: extractor.setType(FilterExpression::GeometryType::Point); break;
case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::Line); break;
case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::LineString); break;
case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break;
default: break;
}

60
src/platform/event.cpp Normal file
View File

@@ -0,0 +1,60 @@
#include <llmr/platform/event.hpp>
#include <cstring>
namespace llmr {
EventSeverity parseEventSeverity(const char *name) {
if (strcmp(name, "DEBUG") == 0) return EventSeverity::Debug;
if (strcmp(name, "INFO") == 0) return EventSeverity::Info;
if (strcmp(name, "TEST") == 0) return EventSeverity::Test;
if (strcmp(name, "WARNING") == 0) return EventSeverity::Warning;
if (strcmp(name, "ERROR") == 0) return EventSeverity::Error;
return EventSeverity(-1);
}
const char *stringifyEventSeverity(EventSeverity eventSeverity) {
switch (eventSeverity) {
case EventSeverity::Debug: return "DEBUG";
case EventSeverity::Info: return "INFO";
case EventSeverity::Test: return "TEST";
case EventSeverity::Warning: return "WARNING";
case EventSeverity::Error: return "ERROR";
default: return "UNKNOWN";
}
}
::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity) {
return os << stringifyEventSeverity(eventSeverity);
}
Event parseEvent(const char *name) {
if (strcmp(name, "General") == 0) return Event::General;
if (strcmp(name, "Setup") == 0) return Event::Setup;
if (strcmp(name, "Shader") == 0) return Event::Shader;
if (strcmp(name, "ParseStyle") == 0) return Event::ParseStyle;
if (strcmp(name, "ParseTile") == 0) return Event::ParseTile;
if (strcmp(name, "Render") == 0) return Event::Render;
if (strcmp(name, "HttpRequest") == 0) return Event::HttpRequest;
return Event(-1);
}
const char *stringifyEvent(Event event) {
switch (event) {
case Event::General: return "General";
case Event::Setup: return "Setup";
case Event::Shader: return "Shader";
case Event::ParseStyle: return "ParseStyle";
case Event::ParseTile: return "ParseTile";
case Event::Render: return "Render";
case Event::HttpRequest: return "HttpRequest";
default: return "Unknown";
}
}
::std::ostream& operator<<(::std::ostream& os, Event event) {
return os << stringifyEvent(event);
}
}

7
src/platform/log.cpp Normal file
View File

@@ -0,0 +1,7 @@
#include <llmr/platform/log.hpp>
namespace llmr {
std::unique_ptr<LogBackend> Log::Backend;
}

View File

@@ -150,7 +150,6 @@ void Painter::renderFill(FillBucket& bucket, std::shared_ptr<StyleLayer> layer_d
if (!bucket.hasData()) return;
const FillProperties &properties = layer_desc->getProperties<FillProperties>();
if (!properties.enabled) return;
if (layer_desc->rasterize && layer_desc->rasterize->isEnabled(id.z)) {
if (pass == Translucent) {

View File

@@ -14,7 +14,6 @@ void Painter::renderIcon(IconBucket& bucket, std::shared_ptr<StyleLayer> layer_d
if (pass == Opaque) return;
const IconProperties &properties = layer_desc->getProperties<IconProperties>();
if (!properties.enabled) return;
// TODO: when translating icon, are we doing this in the bucket already?
// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);

View File

@@ -11,7 +11,6 @@ void Painter::renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_d
if (!bucket.hasData()) return;
const LineProperties &properties = layer_desc->getProperties<LineProperties>();
if (!properties.enabled) return;
float width = properties.width;
float offset = properties.offset / 2;

View File

@@ -9,7 +9,6 @@ void Painter::renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> lay
if (pass == Translucent) return;
const RasterProperties &properties = layer_desc->getProperties<RasterProperties>();
if (!properties.enabled) return;
depthMask(false);

View File

@@ -12,7 +12,6 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_d
if (!bucket.hasData()) return;
const TextProperties &properties = layer_desc->getProperties<TextProperties>();
if (!properties.enabled) return;
mat4 exMatrix;
matrix::copy(exMatrix, projMatrix);

View File

@@ -1,10 +1,8 @@
#include <llmr/shader/shader.hpp>
#include <llmr/platform/gl.hpp>
#if defined(DEBUG)
#include <llmr/util/timer.hpp>
#endif
#include <cstdlib>
#include <cstdio>
#include <llmr/platform/log.hpp>
#include <cstring>
using namespace llmr;
@@ -12,23 +10,17 @@ using namespace llmr;
Shader::Shader(const GLchar *vertSource, const GLchar *fragSource)
: valid(false),
program(0) {
#if defined(DEBUG)
util::timer timer("shader compilation");
#endif
util::timer timer("shader compilation", Event::Shader);
GLuint vertShader;
if (!compileShader(&vertShader, GL_VERTEX_SHADER, vertSource)) {
#if defined(DEBUG)
fprintf(stderr, "Vertex shader failed to compile: %s\n", vertSource);
#endif
Log::Error(Event::Shader, "Vertex shader failed to compile: %s", vertSource);
return;
}
GLuint fragShader;
if (!compileShader(&fragShader, GL_FRAGMENT_SHADER, fragSource)) {
#if defined(DEBUG)
fprintf(stderr, "Fragment shader failed to compile: %s\n", fragSource);
#endif
Log::Error(Event::Shader, "Fragment shader failed to compile: %s", fragSource);
return;
}
@@ -44,20 +36,17 @@ Shader::Shader(const GLchar *vertSource, const GLchar *fragSource)
GLint status;
glLinkProgram(program);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(program, logLength, &logLength, log);
fprintf(stderr, "Program link log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == 0) {
fprintf(stderr, "Program failed to link\n");
GLint logLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(program, logLength, &logLength, log);
Log::Error(Event::Shader, "Program failed to link: %s", log);
free(log);
}
glDeleteShader(vertShader);
vertShader = 0;
glDeleteShader(fragShader);
@@ -73,22 +62,17 @@ Shader::Shader(const GLchar *vertSource, const GLchar *fragSource)
GLint status;
glValidateProgram(program);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(program, logLength, &logLength, log);
fprintf(stderr, "Program validate log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(program, GL_VALIDATE_STATUS, &status);
if (status == 0) {
#if defined(DEBUG)
fprintf(stderr, "Program failed to validate\n");
#endif
GLint logLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(program, logLength, &logLength, log);
Log::Error(Event::Shader, "Program failed to validate: %s", log);
free(log);
}
glDeleteShader(vertShader);
vertShader = 0;
glDeleteShader(fragShader);
@@ -119,19 +103,17 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
glCompileShader(*shader);
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
fprintf(stderr, "Shader compile log:\n%s", log);
free(log);
}
#endif
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
Log::Error(Event::Shader, "Shader failed to compile: %s", log);
free(log);
}
glDeleteShader(*shader);
*shader = 0;
return false;

View File

@@ -175,10 +175,10 @@ std::ostream& operator <<(std::ostream &s, FilterExpression::Operator op) {
std::ostream& operator <<(std::ostream &s, FilterExpression::GeometryType type) {
switch (type) {
case FilterExpression::GeometryType::Point: s << "point"; break;
case FilterExpression::GeometryType::Line: s << "line"; break;
case FilterExpression::GeometryType::Polygon: s << "polygon"; break;
case FilterExpression::GeometryType::Any: s << "any"; break;
case FilterExpression::GeometryType::Point: s << "Point"; break;
case FilterExpression::GeometryType::LineString: s << "LineString"; break;
case FilterExpression::GeometryType::Polygon: s << "Polygon"; break;
case FilterExpression::GeometryType::Any: s << "<Any>"; break;
}
return s;
}
@@ -265,9 +265,9 @@ void FilterExpression::setGeometryType(GeometryType g) {
}
FilterExpression::GeometryType parseGeometryType(const std::string &geometry) {
if (geometry == "point") return FilterExpression::GeometryType::Point;
if (geometry == "line") return FilterExpression::GeometryType::Line;
if (geometry == "polygon") return FilterExpression::GeometryType::Polygon;
if (geometry == "Point") return FilterExpression::GeometryType::Point;
if (geometry == "LineString") return FilterExpression::GeometryType::LineString;
if (geometry == "Polygon") return FilterExpression::GeometryType::Polygon;
return FilterExpression::GeometryType::Any;
}

View File

@@ -34,16 +34,16 @@ bool ExponentialFunction<bool>::evaluate(float z) const {
template <>
float ExponentialFunction<float>::evaluate(float z) const {
return std::fmin(std::fmax(min, value + std::pow(1.75, (z - z_base)) * slope), max);
return std::fmin(std::fmax(min, value + std::pow(exp_base, (z - z_base)) * slope), max);
}
template <>
Color ExponentialFunction<Color>::evaluate(float z) const {
return {{
std::fmin(std::fmax(min[0], value[0] + float(std::pow(1.75, (z - z_base))) * slope), max[0]),
std::fmin(std::fmax(min[1], value[1] + float(std::pow(1.75, (z - z_base))) * slope), max[1]),
std::fmin(std::fmax(min[2], value[2] + float(std::pow(1.75, (z - z_base))) * slope), max[2]),
std::fmin(std::fmax(min[3], value[3] + float(std::pow(1.75, (z - z_base))) * slope), max[3])
std::fmin(std::fmax(min[0], value[0] + float(std::pow(exp_base, (z - z_base))) * slope), max[0]),
std::fmin(std::fmax(min[1], value[1] + float(std::pow(exp_base, (z - z_base))) * slope), max[1]),
std::fmin(std::fmax(min[2], value[2] + float(std::pow(exp_base, (z - z_base))) * slope), max[2]),
std::fmin(std::fmax(min[3], value[3] + float(std::pow(exp_base, (z - z_base))) * slope), max[3])
}};
}

View File

@@ -3,7 +3,6 @@
namespace llmr {
const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::FillEnabled, true },
{ PropertyKey::FillAntialias, true },
{ PropertyKey::FillOpacity, 1.0f },
{ PropertyKey::FillColor, Color({{ 0, 0, 0, 1 }}) },
@@ -11,7 +10,6 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::FillTranslateY, 0.0f },
{ PropertyKey::FillTranslateAnchor, TranslateAnchorType::Map },
{ PropertyKey::LineEnabled, true },
{ PropertyKey::LineOpacity, 1.0f },
{ PropertyKey::LineColor, Color({{ 0, 0, 0, 1 }}) },
{ PropertyKey::LineTranslateX, 0.0f },
@@ -23,12 +21,10 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::LineDashLand, 1.0f },
{ PropertyKey::LineDashGap, -1.0f },
{ PropertyKey::IconEnabled, true },
{ PropertyKey::IconOpacity, 1.0f },
{ PropertyKey::IconRotate, 0.0f },
{ PropertyKey::IconRotateAnchor, RotateAnchorType::Viewport },
{ PropertyKey::TextEnabled, true },
{ PropertyKey::TextOpacity, 1.0f },
{ PropertyKey::TextSize, 16.0f },
{ PropertyKey::TextColor, Color({{ 0, 0, 0, 1 }}) },
@@ -36,10 +32,8 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::TextHaloWidth, 0.25f },
{ PropertyKey::TextHaloBlur, 1.0f },
{ PropertyKey::CompositeEnabled, true },
{ PropertyKey::CompositeOpacity, 1.0f },
{ PropertyKey::RasterEnabled, true },
{ PropertyKey::RasterOpacity, 1.0f },
{ PropertyKey::RasterSpin, 0.0f },
{ PropertyKey::RasterBrightnessLow, 0.0f },

View File

@@ -1,3 +1,4 @@
#include <llmr/map/map.hpp>
#include <llmr/style/style.hpp>
#include <llmr/style/style_layer_group.hpp>
#include <llmr/style/style_parser.hpp>
@@ -12,7 +13,8 @@
namespace llmr {
Style::Style() {
Style::Style(Map &map)
: map(map) {
}
void Style::updateSources() {
@@ -107,7 +109,7 @@ void Style::loadJSON(const uint8_t *const data) {
throw error::style_parse(doc.GetErrorOffset(), doc.GetParseError());
}
StyleParser parser;
StyleParser parser(map);
parser.parse(const_cast<const rapidjson::Document &>(doc));
layers = parser.getLayers();

View File

@@ -0,0 +1,16 @@
#include <llmr/style/style_bucket.hpp>
namespace llmr {
StyleBucket::StyleBucket(StyleLayerType type) {
switch (type) {
case StyleLayerType::Fill: render = StyleBucketFill{}; break;
case StyleLayerType::Line: render = StyleBucketLine{}; break;
case StyleLayerType::Icon: render = StyleBucketIcon{}; break;
case StyleLayerType::Text: render = StyleBucketText{}; break;
case StyleLayerType::Raster: render = StyleBucketRaster{}; break;
default: break;
}
}
}

View File

@@ -11,7 +11,7 @@ StyleLayer::StyleLayer(const std::string &id, std::map<ClassID, ClassProperties>
: id(id), styles(std::move(styles)), rasterize(std::move(rasterize)) {}
bool StyleLayer::isBackground() const {
return id == "background";
return type == StyleLayerType::Background && id == "background";
}
void StyleLayer::setClasses(const std::vector<std::string> &class_names, const timestamp now,
@@ -164,7 +164,6 @@ template <>
void StyleLayer::applyStyleProperties<FillProperties>(const float z, const timestamp now) {
properties.set<FillProperties>();
FillProperties &fill = properties.get<FillProperties>();
applyStyleProperty(PropertyKey::FillEnabled, fill.enabled, z, now);
applyStyleProperty(PropertyKey::FillAntialias, fill.antialias, z, now);
applyStyleProperty(PropertyKey::FillOpacity, fill.opacity, z, now);
applyStyleProperty(PropertyKey::FillColor, fill.fill_color, z, now);
@@ -179,7 +178,6 @@ template <>
void StyleLayer::applyStyleProperties<LineProperties>(const float z, const timestamp now) {
properties.set<LineProperties>();
LineProperties &line = properties.get<LineProperties>();
applyStyleProperty(PropertyKey::LineEnabled, line.enabled, z, now);
applyStyleProperty(PropertyKey::LineOpacity, line.opacity, z, now);
applyStyleProperty(PropertyKey::LineColor, line.color, z, now);
applyStyleProperty(PropertyKey::LineTranslateX, line.translate[0], z, now);
@@ -197,7 +195,6 @@ template <>
void StyleLayer::applyStyleProperties<IconProperties>(const float z, const timestamp now) {
properties.set<IconProperties>();
IconProperties &icon = properties.get<IconProperties>();
applyStyleProperty(PropertyKey::IconEnabled, icon.enabled, z, now);
applyStyleProperty(PropertyKey::IconOpacity, icon.opacity, z, now);
applyStyleProperty(PropertyKey::IconRotate, icon.rotate, z, now);
applyStyleProperty(PropertyKey::IconRotateAnchor, icon.rotate_anchor, z, now);
@@ -207,7 +204,6 @@ template <>
void StyleLayer::applyStyleProperties<TextProperties>(const float z, const timestamp now) {
properties.set<TextProperties>();
TextProperties &text = properties.get<TextProperties>();
applyStyleProperty(PropertyKey::TextEnabled, text.enabled, z, now);
applyStyleProperty(PropertyKey::TextOpacity, text.opacity, z, now);
applyStyleProperty(PropertyKey::TextSize, text.size, z, now);
applyStyleProperty(PropertyKey::TextColor, text.color, z, now);
@@ -220,7 +216,6 @@ template <>
void StyleLayer::applyStyleProperties<CompositeProperties>(const float z, const timestamp now) {
properties.set<CompositeProperties>();
CompositeProperties &composite = properties.get<CompositeProperties>();
applyStyleProperty(PropertyKey::CompositeEnabled, composite.enabled, z, now);
applyStyleProperty(PropertyKey::CompositeOpacity, composite.opacity, z, now);
}
@@ -228,7 +223,6 @@ template <>
void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const timestamp now) {
properties.set<RasterProperties>();
RasterProperties &raster = properties.get<RasterProperties>();
applyStyleProperty(PropertyKey::RasterEnabled, raster.enabled, z, now);
applyStyleProperty(PropertyKey::RasterOpacity, raster.opacity, z, now);
applyStyleProperty(PropertyKey::RasterSpin, raster.spin, z, now);
applyStyleProperty(PropertyKey::RasterBrightnessLow, raster.brightness[0], z, now);
@@ -250,26 +244,17 @@ void StyleLayer::updateProperties(float z, const timestamp now) {
layers->updateProperties(z, now);
}
// Accomodate for different tile size.
if (bucket && bucket->source) {
z += std::log(bucket->source->tile_size / 256.0f) / M_LN2;
}
cleanupAppliedStyleProperties(now);
if (layers) {
applyStyleProperties<CompositeProperties>(z, now);
} else if (bucket) {
switch (bucket->type) {
case BucketType::Fill: applyStyleProperties<FillProperties>(z, now); break;
case BucketType::Line: applyStyleProperties<LineProperties>(z, now); break;
case BucketType::Icon: applyStyleProperties<IconProperties>(z, now); break;
case BucketType::Text: applyStyleProperties<TextProperties>(z, now); break;
case BucketType::Raster: applyStyleProperties<RasterProperties>(z, now); break;
default: properties.set<std::false_type>(); break;
}
} else {
return applyStyleProperties<BackgroundProperties>(z, now);
switch (type) {
case StyleLayerType::Fill: applyStyleProperties<FillProperties>(z, now); break;
case StyleLayerType::Line: applyStyleProperties<LineProperties>(z, now); break;
case StyleLayerType::Icon: applyStyleProperties<IconProperties>(z, now); break;
case StyleLayerType::Text: applyStyleProperties<TextProperties>(z, now); break;
case StyleLayerType::Raster: applyStyleProperties<RasterProperties>(z, now); break;
case StyleLayerType::Composite: applyStyleProperties<CompositeProperties>(z, now); break;
case StyleLayerType::Background: applyStyleProperties<BackgroundProperties>(z, now); break;
default: properties.set<std::false_type>(); break;
}
}

View File

@@ -1,3 +1,4 @@
#include <llmr/map/map.hpp>
#include <llmr/style/style_parser.hpp>
#include <llmr/style/style_layer_group.hpp>
#include <llmr/util/constants.hpp>
@@ -8,6 +9,10 @@ namespace llmr {
using JSVal = const rapidjson::Value&;
StyleParser::StyleParser(Map &map)
: map(map) {
}
void StyleParser::parse(JSVal document) {
if (document.HasMember("constants")) {
parseConstants(document["constants"]);
@@ -165,11 +170,13 @@ void StyleParser::parseSources(JSVal value) {
parseRenderProperty(itr->value, type, "type", parseSourceType);
parseRenderProperty(itr->value, url, "url");
parseRenderProperty(itr->value, tile_size, "tileSize");
if (type == SourceType::Raster) {
parseRenderProperty(itr->value, tile_size, "tileSize");
}
parseRenderProperty(itr->value, min_zoom, "minZoom");
parseRenderProperty(itr->value, max_zoom, "maxZoom");
sources.emplace(std::move(name), std::make_shared<Source>(type, url, tile_size, min_zoom, max_zoom));
sources.emplace(std::move(name), std::make_shared<Source>(type, url, tile_size, min_zoom, max_zoom, map.getAccessToken()));
}
} else {
throw Style::exception("sources must be an object");
@@ -266,11 +273,12 @@ std::tuple<bool, Function<T>> StyleParser::parseFunction(JSVal value) {
return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) };
}
const float z_base = parseFunctionArgument<float>(value["z"]);
const float exp_base = value.HasMember("base") ? parseFunctionArgument<float>(value["base"]) : 1.75;
const T val = parseFunctionArgument<T>(value["val"]);
const float slope = value.HasMember("slope") ? parseFunctionArgument<float>(value["slope"]) : 1;
const T min = value.HasMember("min") ? parseFunctionArgument<T>(value["min"]) : T();
const T max = value.HasMember("max") ? parseFunctionArgument<T>(value["max"]) : T();
return std::tuple<bool, Function<T>> { true, ExponentialFunction<T>(val, z_base, slope, min, max) };
return std::tuple<bool, Function<T>> { true, ExponentialFunction<T>(val, z_base, exp_base, slope, min, max) };
}
else if (type == "stops") {
if (!value.HasMember("stops")) {
@@ -548,6 +556,15 @@ void StyleParser::parseLayer(std::pair<JSVal, std::shared_ptr<StyleLayer>> &pair
return;
}
if (value.HasMember("type")) {
JSVal type = value["type"];
if (!type.IsString()) {
fprintf(stderr, "[WARNING] layer type of '%s' must be a string\n", layer->id.c_str());
} else {
layer->type = parseStyleLayerType({ type.GetString(), type.GetStringLength() });
}
}
// Make sure we have not previously attempted to parse this layer.
if (std::find(stack.begin(), stack.end(), layer.get()) != stack.end()) {
fprintf(stderr, "[WARNING] layer reference of '%s' is circular\n", layer->id.c_str());
@@ -583,8 +600,6 @@ void StyleParser::parseStyles(JSVal value, std::map<ClassID, ClassProperties> &s
void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
using Key = PropertyKey;
parseOptionalProperty<Function<bool>>("fill-enabled", Key::FillEnabled, klass, value);
parseOptionalProperty<PropertyTransition>("transition-fill-enabled", Key::FillEnabled, klass, value);
parseOptionalProperty<Function<bool>>("fill-antialias", Key::FillAntialias, klass, value);
parseOptionalProperty<Function<float>>("fill-opacity", Key::FillOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-fill-opacity", Key::FillOpacity, klass, value);
@@ -597,8 +612,6 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<TranslateAnchorType>("fill-translate-anchor", Key::FillTranslateAnchor, klass, value);
parseOptionalProperty<std::string>("fill-image", Key::FillImage, klass, value);
parseOptionalProperty<Function<bool>>("line-enabled", Key::LineEnabled, klass, value);
parseOptionalProperty<PropertyTransition>("transition-line-enabled", Key::LineEnabled, klass, value);
parseOptionalProperty<Function<float>>("line-opacity", Key::LineOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-line-opacity", Key::LineOpacity, klass, value);
parseOptionalProperty<Function<Color>>("line-color", Key::LineColor, klass, value);
@@ -616,15 +629,11 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<PropertyTransition>("transition-line-dasharray", Key::LineDashArray, klass, value);
parseOptionalProperty<std::string>("line-image", Key::LineImage, klass, value);
parseOptionalProperty<Function<bool>>("icon-enabled", Key::IconEnabled, klass, value);
parseOptionalProperty<PropertyTransition>("transition-icon-enabled", Key::IconEnabled, klass, value);
parseOptionalProperty<Function<float>>("icon-opacity", Key::IconOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-icon-opacity", Key::IconOpacity, klass, value);
parseOptionalProperty<Function<float>>("icon-rotate", Key::IconRotate, klass, value);
parseOptionalProperty<RotateAnchorType>("icon-rotate-anchor", Key::IconRotateAnchor, klass, value);
parseOptionalProperty<Function<bool>>("text-enabled", Key::TextEnabled, klass, value);
parseOptionalProperty<PropertyTransition>("transition-text-enabled", Key::TextEnabled, klass, value);
parseOptionalProperty<Function<float>>("text-opacity", Key::TextOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-text-opacity", Key::TextOpacity, klass, value);
parseOptionalProperty<Function<float>>("text-size", Key::TextSize, klass, value);
@@ -638,13 +647,9 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<Function<float>>("text-halo-blur", Key::TextHaloBlur, klass, value);
parseOptionalProperty<PropertyTransition>("transition-text-halo-blur", Key::TextHaloBlur, klass, value);
parseOptionalProperty<Function<bool>>("composite-enabled", Key::CompositeEnabled, klass, value);
parseOptionalProperty<PropertyTransition>("transition-composite-enabled", Key::CompositeEnabled, klass, value);
parseOptionalProperty<Function<float>>("composite-opacity", Key::CompositeOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-composite-opacity", Key::CompositeOpacity, klass, value);
parseOptionalProperty<Function<bool>>("raster-enabled", Key::RasterEnabled, klass, value);
parseOptionalProperty<PropertyTransition>("transition-raster-enabled", Key::RasterEnabled, klass, value);
parseOptionalProperty<Function<float>>("raster-opacity", Key::RasterOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-raster-opacity", Key::RasterOpacity, klass, value);
parseOptionalProperty<Function<float>>("raster-spin", Key::RasterSpin, klass, value);
@@ -694,20 +699,24 @@ void StyleParser::parseReference(JSVal value, std::shared_ptr<StyleLayer> &layer
parseLayer(it->second);
stack.pop_front();
std::shared_ptr<StyleLayer> reference = it->second.second;
layer->type = reference->type;
if (reference->layers) {
fprintf(stderr, "[WARNING] layer '%s' references composite layer\n", layer->id.c_str());
// We cannot parse this layer further.
return;
} else {
layer->bucket = reference->bucket;
}
layer->bucket = reference->bucket;
}
#pragma mark - Parse Bucket
void StyleParser::parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer) {
layer->bucket = std::make_shared<StyleBucket>();
layer->bucket = std::make_shared<StyleBucket>(layer->type);
// We name the buckets according to the layer that defined it.
layer->bucket->name = layer->id;
@@ -844,23 +853,14 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
StyleBucket &bucket = *layer->bucket;
if (value.HasMember("type")) {
JSVal type = value["type"];
if (type.IsString()) {
bucket.type = parseBucketType({ type.GetString(), type.GetStringLength() });
}
}
switch (bucket.type) {
case BucketType::Fill: {
bucket.render = StyleBucketFill{};
switch (layer->type) {
case StyleLayerType::Fill: {
StyleBucketFill &render = bucket.render.get<StyleBucketFill>();
parseRenderProperty(value, render.winding, "fill-winding", parseWindingType);
} break;
case BucketType::Line: {
bucket.render = StyleBucketLine{};
case StyleLayerType::Line: {
StyleBucketLine &render = bucket.render.get<StyleBucketLine>();
parseRenderProperty(value, render.cap, "line-cap", parseCapType);
@@ -869,8 +869,7 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
parseRenderProperty(value, render.round_limit, "line-round-limit");
} break;
case BucketType::Icon: {
bucket.render = StyleBucketIcon{};
case StyleLayerType::Icon: {
StyleBucketIcon &render = bucket.render.get<StyleBucketIcon>();
parseRenderProperty(value, render.size, "icon-size");
@@ -884,8 +883,7 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
parseRenderProperty(value, render.translate_anchor, "icon-translate-anchor", parseTranslateAnchorType);
} break;
case BucketType::Text: {
bucket.render = StyleBucketText{};
case StyleLayerType::Text: {
StyleBucketText &render = bucket.render.get<StyleBucketText>();
parseRenderProperty(value, render.field, "text-field");
@@ -915,14 +913,8 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
}
parseRenderProperty(value, render.translate_anchor, "text-translate-anchor", parseTranslateAnchorType);
} break;
case BucketType::Raster: {
bucket.render = StyleBucketRaster{};
} break;
default:
layer->bucket.reset();
fprintf(stderr, "[WARNING] bucket type of layer '%s' is invalid\n", layer->id.c_str());
// There are no render properties for these layer types.
break;
}
}

View File

@@ -4,28 +4,32 @@
namespace llmr {
BucketType parseBucketType(const std::string &type) {
if (type == "fill") return BucketType::Fill;
if (type == "line") return BucketType::Line;
if (type == "icon") return BucketType::Icon;
if (type == "text") return BucketType::Text;
if (type == "raster") return BucketType::Raster;
return BucketType::None;
StyleLayerType parseStyleLayerType(const std::string &type) {
if (type == "fill") return StyleLayerType::Fill;
if (type == "line") return StyleLayerType::Line;
if (type == "icon") return StyleLayerType::Icon;
if (type == "text") return StyleLayerType::Text;
if (type == "raster") return StyleLayerType::Raster;
if (type == "composite") return StyleLayerType::Composite;
if (type == "background") return StyleLayerType::Background;
return StyleLayerType::Unknown;
}
const char *stringifyBucketType(BucketType type) {
const char *stringifyStyleLayerType(StyleLayerType type) {
switch (type) {
case BucketType::Fill: return "fill";
case BucketType::Line: return "line";
case BucketType::Icon: return "icon";
case BucketType::Text: return "text";
case BucketType::Raster: return "raster";
default: return "none";
case StyleLayerType::Fill: return "fill";
case StyleLayerType::Line: return "line";
case StyleLayerType::Icon: return "icon";
case StyleLayerType::Text: return "text";
case StyleLayerType::Raster: return "raster";
case StyleLayerType::Composite: return "composite";
case StyleLayerType::Background: return "background";
default: return "unknown";
}
}
std::ostream& operator<<(std::ostream& os, BucketType type) {
return os << stringifyBucketType(type);
std::ostream& operator<<(std::ostream& os, StyleLayerType type) {
return os << stringifyStyleLayerType(type);
}
}

View File

@@ -120,12 +120,11 @@ GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, Gl
: future(promise.get_future().share())
{
// Load the glyph set URL
const std::map<std::string, std::string> tokens {{
{ "fontstack", fontStack },
{ "range", std::to_string(glyphRange.first) + "-" + std::to_string(glyphRange.second) }
}};
std::string url = util::replaceTokens(glyphURL, tokens);
std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
if (name == "fontstack") return fontStack;
if (name == "range") return std::to_string(glyphRange.first) + "-" + std::to_string(glyphRange.second);
return "";
});
// TODO: Find more reliable URL normalization function
std::replace(url.begin(), url.end(), ' ', '+');

View File

@@ -1,28 +1,29 @@
#ifndef DISABLE_TIMER
#include <llmr/util/timer.hpp>
#include <llmr/util/time.hpp>
#include <llmr/platform/log.hpp>
#include <iostream>
#include <atomic>
using namespace llmr::util;
std::atomic<int> indent;
timer::timer(Event event)
: event(event), start(now()) {}
timer::timer() : start(now()) {
indent++;
}
timer::timer(EventSeverity severity, Event event)
: severity(severity), event(event), start(now()) {}
timer::timer(const std::string &name) : name(name), start(now()) {
indent++;
}
timer::timer(const std::string &name, Event event)
: name(name), event(event), start(now()) {}
timer::timer(const std::string &name, EventSeverity severity, Event event)
: name(name), severity(severity), event(event), start(now()) {}
void timer::report(const std::string &name) {
timestamp duration = now() - start;
std::cerr << std::string((indent - 1) * 4, ' ')
<< name << ": "
<< (double)(duration) / 1_millisecond
<< "ms" << std::endl;
Log::Record(severity, event, name + ": " + std::to_string((double)(duration) / 1_millisecond) + "ms");
start += duration;
}
@@ -30,6 +31,5 @@ timer::~timer() {
if (name.size()) {
report(name);
}
indent--;
}
#endif

46
test/fixtures/fixture_log.cpp vendored Normal file
View File

@@ -0,0 +1,46 @@
#include "fixture_log.hpp"
#include <iostream>
namespace llmr {
FixtureLogBackend::~FixtureLogBackend() {
std::cerr << unchecked();
}
size_t FixtureLogBackend::count(const LogMessage &message) const {
size_t count = 0;
for (const LogMessage &msg : messages) {
if (msg == message) {
count++;
msg.checked = true;
}
}
return count;
}
std::vector<FixtureLogBackend::LogMessage> FixtureLogBackend::unchecked() const {
std::vector<LogMessage> unchecked;
for (const LogMessage &msg : messages) {
if (!msg.checked) {
unchecked.push_back(msg);
}
}
return unchecked;
}
::std::ostream& operator<<(::std::ostream& os, const std::vector<FixtureLogBackend::LogMessage>& messages) {
for (const FixtureLogBackend::LogMessage &message : messages) {
os << "- " << message;
}
return os;
}
::std::ostream& operator<<(::std::ostream& os, const FixtureLogBackend::LogMessage& message) {
os << "[\"" << message.severity.get() << "\", \"" << message.event.get();
if (message.code) os << "\", " << message.code.get();
if (message.msg) os << ", \"" << message.msg.get();
return os << "\"]" << std::endl;
}
}

78
test/fixtures/fixture_log.hpp vendored Normal file
View File

@@ -0,0 +1,78 @@
#ifndef LLMR_TEST_FIXTURE_LOG
#define LLMR_TEST_FIXTURE_LOG
#include <llmr/platform/log.hpp>
#include <boost/optional.hpp>
#include <vector>
namespace llmr {
class FixtureLogBackend : public LogBackend {
public:
struct LogMessage {
inline LogMessage(EventSeverity severity, Event event, int64_t code, const std::string &msg)
: severity(severity), event(event), code(code), msg(msg) {}
inline LogMessage(EventSeverity severity, Event event, int64_t code)
: severity(severity), event(event), code(code) {}
inline LogMessage(EventSeverity severity, Event event, const std::string &msg)
: severity(severity), event(event), msg(msg) {}
inline LogMessage(EventSeverity severity, Event event)
: severity(severity), event(event) {}
inline bool operator==(const LogMessage &rhs) const {
return (!severity || !rhs.severity || severity.get() == rhs.severity.get()) &&
(!event || !rhs.event || event.get() == rhs.event.get()) &&
(!code || !rhs.code || code.get() == rhs.code.get()) &&
(!msg || !rhs.msg || msg.get() == rhs.msg.get());
}
const boost::optional<EventSeverity> severity;
const boost::optional<Event> event;
const boost::optional<int64_t> code;
const boost::optional<std::string> msg;
mutable bool checked = false;
};
~FixtureLogBackend();
void record(EventSeverity severity, Event event, const std::string &msg) {
messages.emplace_back(severity, event, msg);
}
void record(EventSeverity severity, Event event, const char* format, ...) {
va_list args;
va_start(args, format);
const int len = vsnprintf(NULL, 0, format, args);
va_end(args);
std::unique_ptr<char[]> buffer(new char[len + 1]);
va_start(args, format);
vsnprintf(buffer.get(), len + 1, format, args);
va_end(args);
messages.emplace_back(severity, event, std::string { buffer.get(), len });
}
void record(EventSeverity severity, Event event, int64_t code) {
messages.emplace_back(severity, event, code);
}
void record(EventSeverity severity, Event event, int64_t code, const std::string &msg) {
messages.emplace_back(severity, event, code, msg);
}
size_t count(const LogMessage &message) const;
std::vector<LogMessage> unchecked() const;
public:
std::vector<LogMessage> messages;
};
::std::ostream& operator<<(::std::ostream& os, const std::vector<FixtureLogBackend::LogMessage>& messages);
::std::ostream& operator<<(::std::ostream& os, const FixtureLogBackend::LogMessage& message);
}
#endif

View File

@@ -1,6 +1,7 @@
#include <llmr/platform/platform.hpp>
#include <llmr/platform/request.hpp>
#include <llmr/util/uv.hpp>
#include <llmr/platform/log.hpp>
const std::string base_directory = []{
std::string fn = __FILE__;
@@ -40,6 +41,7 @@ platform::request_http(const std::string &url,
if (err < 0) {
req->res->code = err;
req->res->error_message = uv_strerror(err);
Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err));
req->complete();
return req;
}
@@ -52,6 +54,7 @@ platform::request_http(const std::string &url,
if (err < 0) {
req->res->code = err;
req->res->error_message = uv_strerror(err);
Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err));
req->complete();
return req;
}
@@ -69,6 +72,7 @@ platform::request_http(const std::string &url,
if (err < 0) {
req->res->code = err;
req->res->error_message = uv_strerror(err);
Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err));
req->complete();
return req;
}
@@ -80,12 +84,14 @@ platform::request_http(const std::string &url,
if (err < 0) {
req->res->code = err;
req->res->error_message = uv_strerror(err);
Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err));
req->complete();
return req;
}
req->res->body.swap(body);
req->res->code = 200;
Log::Info(Event::HttpRequest, 200, url);
req->complete();
return req;

View File

@@ -1,8 +0,0 @@
{
"zoom": 0,
"latitude": 0,
"longitude": 0,
"angle": 0,
"width": 512,
"height": 512
}

View File

@@ -1,8 +0,0 @@
{
"zoom": 0,
"latitude": 0,
"longitude": 0,
"angle": 0,
"width": 512,
"height": 512
}

View File

@@ -0,0 +1,27 @@
{
"default": {
"zoom": 14,
"center": [52.499167, 13.418056],
"height": 256,
"log": [
[1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"],
[1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"],
[1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
[1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
[4, "INFO", "HttpRequest"]
]
},
"colored": {
"zoom": 14,
"center": [52.499167, 13.418056],
"height": 256,
"classes": ["colored"],
"log": [
[1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"],
[1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"],
[1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
[1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
[4, "INFO", "HttpRequest"]
]
}
}

View File

@@ -0,0 +1,33 @@
{
"version": 3,
"sources": {
"mapbox": {
"type": "vector",
"url": "tiles/{z}-{x}-{y}.vector.pbf",
"tileSize": 512,
"maxZoom": 14
}
},
"layers": [
{
"id": "background",
"type": "background",
"style": {
"background-color": "white"
}
},
{
"id": "road",
"source": "mapbox",
"source-layer": "road",
"type": "line",
"style": {
"line-width": 2,
"line-color": "#3590db"
},
"style.colored": {
"line-color": "#222222"
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Some files were not shown because too many files have changed in this diff Show More