diff --git a/bin/build-style-json.js b/bin/build-style-json.js deleted file mode 100755 index 0daa6d1f1..000000000 --- a/bin/build-style-json.js +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -var fs = require('fs'); - -var name = 'style'; -var data = JSON.stringify(require('./style'), null, 4).split('\n').map(function(str) { - return JSON.stringify(str + '\n'); -}); - -var length = data.length; - -var header = '// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.\n\n'; -header += '#ifndef LLMR_STYLE_RESOURCES\n'; -header += '#define LLMR_STYLE_RESOURCES\n'; -header += '\n'; -header += 'namespace llmr {\n'; -header += 'namespace resources {\n'; -header += '\n'; -header += 'extern const unsigned char ' + name + '[];\n'; -header += 'extern const unsigned long ' + name + '_size;\n'; -header += '\n'; -header += '}\n'; -header += '}\n'; -header += '\n'; -header += '#endif\n'; -fs.writeFileSync('include/llmr/style/resources.hpp', header); - -var code = '// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.\n'; -code += '#include \n'; -code += '\n'; -code += 'using namespace llmr;\n'; -code += '\n'; -code += 'const unsigned char resources::' + name + '[] =\n'; -code += ' ' + data.join('\n ') + ''; -code += ';\n'; -code += 'const unsigned long resources::' + name + '_size = sizeof(resources::' + name + ');\n'; - -fs.writeFileSync('src/style/resources.cpp', code); - diff --git a/bin/build-style.js b/bin/build-style.js index 3931d00d9..970ccacda 100755 --- a/bin/build-style.js +++ b/bin/build-style.js @@ -4,7 +4,7 @@ var fs = require('fs'); var name = 'style'; -var data = fs.readFileSync('resources/style.pbf'); +var data = JSON.stringify(require('./style')); var length = data.length; @@ -29,17 +29,7 @@ code += '#include \n'; code += '\n'; code += 'using namespace llmr;\n'; code += '\n'; -code += 'const unsigned char resources::' + name + '[] = {\n'; - - -for (var i = 0; i < data.length; i += 16) { - if (i > 0) { - code += ',\n'; - } - var part = data.slice(i, i + 16); - code += ' ' + Array.prototype.join.call(part, ', '); -} -code += '\n};\n'; +code += 'const unsigned char resources::' + name + '[] = R"JSON(' + data + ')JSON";\n'; code += 'const unsigned long resources::' + name + '_size = sizeof(resources::' + name + ');\n'; fs.writeFileSync('src/style/resources.cpp', code); diff --git a/bin/convert-style.js b/bin/convert-style.js deleted file mode 100755 index a79f46cf7..000000000 --- a/bin/convert-style.js +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -var style = require('./style.js'); -var Protobuf = require('./protobuf.js'); -var fs = require('fs'); - -var pbf = new Protobuf(); - -// enum -var bucket_type = { - fill: 1, - line: 2, - point: 3 -}; - -// enum -var cap_type = { - round: 1, - butt: 2, - square: 3 -}; - -// enum -var join_type = { - miter: 1, - bevel: 2, - round: 3 -}; - -// enum -var property_type = { - 'null': 1, - constant: 2, - stops: 3, - linear: 4 -}; - - -function createValue(value) { - var pbf = new Protobuf(); - - if (typeof value === 'string') { - pbf.writeTaggedString(1 /* string_value */, value); - } else if (typeof value === 'boolean') { - pbf.writeTaggedBoolean(7 /* bool_value */, value); - } else { - // TODO: - console.warn('encode value: %s', value); - process.exit(); - } - - return pbf; -} - -function createBucket(bucket, name) { - var pbf = new Protobuf(); - pbf.writeTaggedString(1 /* name */, name); - pbf.writeTaggedVarint(2 /* type */, bucket_type[bucket.type]); - - pbf.writeTaggedString(3 /* source_name */, bucket.datasource); - pbf.writeTaggedString(4 /* source_layer */, bucket.layer); - if (bucket.field) { - pbf.writeTaggedString(5 /* source_field */, bucket.field); - var values = Array.isArray(bucket.value) ? bucket.value : [bucket.value]; - for (var i = 0; i < values.length; i++) { - pbf.writeMessage(6 /* source_value */, createValue(values[i])); - } - } - if (bucket.cap) { - pbf.writeTaggedVarint(7 /* cap */, cap_type[bucket.cap]); - } - if (bucket.join) { - pbf.writeTaggedVarint(8 /* join */, join_type[bucket.join]); - } - - // TODO: font stuff - - return pbf; -} - -function createStructure(structure) { - var pbf = new Protobuf(); - pbf.writeTaggedString(1 /* name */, structure.name); - if (structure.bucket) { - pbf.writeTaggedString(2 /* bucket_name */, structure.bucket); - } else if (structure.layers) { - for (var i = 0; i < structure.layers.length; i++) { - pbf.writeMessage(3 /* child_layer */, createStructure(structure.layers[i])); - } - } - return pbf; -} - -function createProperty(type, values) { - var pbf = new Protobuf(); - pbf.writeTaggedVarint(1 /* function */, property_type[type]); - pbf.writePackedFloats(2 /* value */, values.map(function(v) { return +v; })); - - return pbf; -} - -function convertProperty(orig_values) { - if (Array.isArray(orig_values)) { - var type = orig_values[0]; - var values = []; - for (var i = 1; i < orig_values.length; i++) { - if (orig_values[0] === 'stops') { - values.push(orig_values[i].z, orig_values[i].val); - } else { - values.push(orig_values[i]); - } - } - return createProperty(type, values); - } else { - return createProperty('constant', [orig_values]); - } -} - -function createFillClass(layer, name) { - var pbf = new Protobuf(); - pbf.writeTaggedString(1 /* layer_name */, name); - - if ('antialias' in layer) { - pbf.writeMessage(4 /* antialias */, createProperty('constant', [layer.antialias])); - } - - if ('color' in layer) { - var color = layer.color.match(/^#([0-9a-f]{6})$/i); - if (!color) { - console.warn('invalid color'); - } else { - pbf.writeTaggedUInt32(5 /* fill_color */, parseInt(color[1] + 'ff', 16)); - } - } - - if ('stroke' in layer) { - var color = layer.stroke.match(/^#([0-9a-f]{6})$/i); - if (!color) { - console.warn('invalid color'); - } else { - pbf.writeTaggedUInt32(6 /* stroke_color */, parseInt(color[1] + 'ff', 16)); - } - } - - if ('opacity' in layer) { - pbf.writeMessage(7 /* opacity */, convertProperty(layer.opacity)); - } - - if ('image' in layer) { - pbf.writeTaggedString(8 /* image */, layer.image); - } - - return pbf; -} - -function createLineClass(layer, name) { - var pbf = new Protobuf(); - pbf.writeTaggedString(1 /* layer_name */, name); - - if ('color' in layer) { - var color = layer.color.match(/^#([0-9a-f]{6})$/i); - if (!color) { - console.warn('invalid color'); - } else { - pbf.writeTaggedUInt32(3 /* color */, parseInt(color[1] + 'ff', 16)); - } - } - - if ('width' in layer) { - pbf.writeMessage(4 /* width */, convertProperty(layer.width)); - } - - if ('opacity' in layer) { - pbf.writeMessage(6 /* opacity */, convertProperty(layer.opacity)); - } - - return pbf; -} - -function createMarkerClass(layer, name) { - var pbf = new Protobuf(); - pbf.writeTaggedString(1 /* layer_name */, name); - - if ('color' in layer) { - var color = layer.color.match(/^#([0-9a-f]{6})$/i); - if (!color) { - console.warn('invalid color'); - } else { - pbf.writeTaggedUInt32(3 /* color */, parseInt(color[1] + 'ff', 16)); - } - } - - if ('size' in layer) { - pbf.writeMessage(4 /* size */, convertProperty(layer.size)); - } - - if ('opacity' in layer) { - pbf.writeMessage(6 /* opacity */, convertProperty(layer.opacity)); - } - - if ('image' in layer) { - pbf.writeTaggedString(8 /* image */, layer.image); - } - - return pbf; -} - -function createClass(klass) { - var pbf = new Protobuf(); - pbf.writeTaggedString(1 /* name */, klass.name); - for (var name in klass.layers) { - switch (klass.layers[name].type) { - case 'fill': pbf.writeMessage(2 /* fill */, createFillClass(klass.layers[name], name)); break; - case 'line': pbf.writeMessage(3 /* line */, createLineClass(klass.layers[name], name)); break; - case 'marker': pbf.writeMessage(4 /* marker */, createMarkerClass(klass.layers[name], name)); break; - } - } - return pbf; -} - -for (var name in style.buckets) { - var bucket = style.buckets[name]; - pbf.writeMessage(1 /* bucket */, createBucket(bucket, name)); -} - -for (var i = 0; i < style.structure.length; i++) { - var structure = style.structure[i]; - pbf.writeMessage(2 /* structure */, createStructure(structure)); -} - -for (var i = 0; i < style.classes.length; i++) { - var klass = style.classes[i]; - pbf.writeMessage(3 /* class */, createClass(klass)); -} - -fs.writeFileSync('resources/style.pbf', pbf.finish()); diff --git a/bin/style.js b/bin/style.js index 50b365c1d..becf1cdf7 100644 --- a/bin/style.js +++ b/bin/style.js @@ -171,35 +171,35 @@ module.exports = { ], }, "alcohol_poi": { - "type": "marker", + "type": "point", "color": "#cccccc", "size": 18, "image": "alcohol-shop", "opacity": [ "linear", 15, 0, 1.0, 0, 0.75 ] }, "cafe_poi": { - "type": "marker", + "type": "point", "color": "#cccccc", "size": 18, "image": "cafe", "opacity": [ "linear", 15, 0, 1.0, 0, 0.75 ] }, "embassy_poi": { - "type": "marker", + "type": "point", "color": "#cccccc", "size": 18, "image": "embassy", "opacity": [ "linear", 15, 0, 1.0, 0, 0.75 ] }, "park_poi": { - "type": "marker", + "type": "point", "color": "#cccccc", "size": 18, "image": "park", "opacity": [ "linear", 15, 0, 1.0, 0, 0.75 ] }, "restaurant_poi": { - "type": "marker", + "type": "point", "color": "#cccccc", "size": 18, "image": "restaurant", diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp index eab7b46a9..efb46fd39 100644 --- a/include/llmr/style/class_description.hpp +++ b/include/llmr/style/class_description.hpp @@ -10,6 +10,7 @@ namespace llmr { class ClassDescription { public: + BackgroundClass background; std::map fill; std::map line; std::map point; diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 79b906cd5..9d05b4ad9 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -112,6 +112,10 @@ struct FillProperties { std::string image; }; +struct BackgroundClass { + Color fill_color = {{ 0, 0, 0, 0 }}; +}; + } #endif diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 7a491d810..2b7562244 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -18,15 +18,15 @@ namespace llmr { class Sprite; class Style { +public: + struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} }; + public: Style(); void reset(); - void load(const uint8_t *const data, size_t bytes); - // This is commented out because it is not fully implemented yet. For now, - // we keep using the protobuf stylesheet format - // void loadJSON(const std::string& data); + void loadJSON(const uint8_t *const data, size_t bytes); void cascade(float z); diff --git a/llmr.gyp b/llmr.gyp index 76174e2e6..072f56901 100644 --- a/llmr.gyp +++ b/llmr.gyp @@ -20,20 +20,10 @@ 'action': ['bin/build-shaders.js'], }, { - 'action_name': 'Convert Style to Protobuf', + 'action_name': 'Build Stylesheet', 'inputs': [ 'bin/style.js' ], - 'outputs': [ - 'resources/style.pbf' - ], - 'action': ['bin/convert-style.js'], - }, - { - 'action_name': 'Update Style Resources', - 'inputs': [ - 'resources/style.pbf' - ], 'outputs': [ 'include/llmr/style/resources.hpp', 'src/style/resources.cpp' diff --git a/resources/style.pbf b/resources/style.pbf deleted file mode 100644 index 0cec5c892..000000000 Binary files a/resources/style.pbf and /dev/null differ diff --git a/src/map/map.cpp b/src/map/map.cpp index 852732d37..5e13727f2 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -30,8 +30,7 @@ void Map::setup(float pixelRatio) { style.sprite = std::make_shared(); style.sprite->load(kSpriteURL, pixel_ratio); - style.load(resources::style, resources::style_size); - // style.loadJSON((const char *)resources::style, resources::style_size); + style.loadJSON(resources::style, resources::style_size); } void Map::loadSprite(const std::string& url) { @@ -39,7 +38,7 @@ void Map::loadSprite(const std::string& url) { } void Map::loadStyle(const uint8_t *const data, uint32_t bytes) { - style.load(data, bytes); + style.loadJSON(data, bytes); update(); } diff --git a/src/style/resources.cpp b/src/style/resources.cpp index 3b26d8c2d..0ae7c259a 100644 --- a/src/style/resources.cpp +++ b/src/style/resources.cpp @@ -3,113 +3,5 @@ using namespace llmr; -const unsigned char resources::style[] = { - 10, 25, 10, 5, 119, 97, 116, 101, 114, 16, 1, 26, 7, 115, 116, 114, - 101, 101, 116, 115, 34, 5, 119, 97, 116, 101, 114, 10, 60, 10, 10, 114, - 111, 97, 100, 95, 108, 97, 114, 103, 101, 16, 2, 26, 7, 115, 116, 114, - 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, - 115, 50, 10, 10, 8, 109, 111, 116, 111, 114, 119, 97, 121, 50, 6, 10, - 4, 109, 97, 105, 110, 56, 1, 64, 3, 10, 52, 10, 12, 114, 111, 97, - 100, 95, 114, 101, 103, 117, 108, 97, 114, 16, 2, 26, 7, 115, 116, 114, - 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, - 115, 50, 8, 10, 6, 115, 116, 114, 101, 101, 116, 56, 1, 64, 3, 10, - 60, 10, 12, 114, 111, 97, 100, 95, 108, 105, 109, 105, 116, 101, 100, 16, - 2, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, - 42, 5, 99, 108, 97, 115, 115, 50, 16, 10, 14, 115, 116, 114, 101, 101, - 116, 95, 108, 105, 109, 105, 116, 101, 100, 56, 1, 64, 3, 10, 41, 10, - 4, 112, 97, 114, 107, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, - 34, 7, 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, - 50, 6, 10, 4, 112, 97, 114, 107, 10, 41, 10, 4, 119, 111, 111, 100, - 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, - 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 6, 10, 4, 119, - 111, 111, 100, 10, 45, 10, 6, 115, 99, 104, 111, 111, 108, 16, 1, 26, - 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, 115, - 101, 42, 5, 99, 108, 97, 115, 115, 50, 8, 10, 6, 115, 99, 104, 111, - 111, 108, 10, 49, 10, 8, 99, 101, 109, 101, 116, 101, 114, 121, 16, 1, - 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, - 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 10, 10, 8, 99, 101, 109, - 101, 116, 101, 114, 121, 10, 53, 10, 10, 105, 110, 100, 117, 115, 116, 114, - 105, 97, 108, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, - 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 12, - 10, 10, 105, 110, 100, 117, 115, 116, 114, 105, 97, 108, 10, 31, 10, 8, - 98, 117, 105, 108, 100, 105, 110, 103, 16, 1, 26, 7, 115, 116, 114, 101, - 101, 116, 115, 34, 8, 98, 117, 105, 108, 100, 105, 110, 103, 10, 52, 10, - 11, 97, 108, 99, 111, 104, 111, 108, 95, 112, 111, 105, 16, 3, 26, 7, - 115, 116, 114, 101, 101, 116, 115, 34, 9, 112, 111, 105, 95, 108, 97, 98, - 101, 108, 42, 4, 116, 121, 112, 101, 50, 9, 10, 7, 65, 108, 99, 111, - 104, 111, 108, 10, 46, 10, 8, 99, 97, 102, 101, 95, 112, 111, 105, 16, - 3, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 9, 112, 111, 105, 95, - 108, 97, 98, 101, 108, 42, 4, 116, 121, 112, 101, 50, 6, 10, 4, 67, - 97, 102, 101, 10, 52, 10, 11, 101, 109, 98, 97, 115, 115, 121, 95, 112, - 111, 105, 16, 3, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 9, 112, - 111, 105, 95, 108, 97, 98, 101, 108, 42, 4, 116, 121, 112, 101, 50, 9, - 10, 7, 69, 109, 98, 97, 115, 115, 121, 10, 46, 10, 8, 112, 97, 114, - 107, 95, 112, 111, 105, 16, 3, 26, 7, 115, 116, 114, 101, 101, 116, 115, - 34, 9, 112, 111, 105, 95, 108, 97, 98, 101, 108, 42, 4, 116, 121, 112, - 101, 50, 6, 10, 4, 80, 97, 114, 107, 10, 58, 10, 14, 114, 101, 115, - 116, 97, 117, 114, 97, 110, 116, 95, 112, 111, 105, 16, 3, 26, 7, 115, - 116, 114, 101, 101, 116, 115, 34, 9, 112, 111, 105, 95, 108, 97, 98, 101, - 108, 42, 4, 116, 121, 112, 101, 50, 12, 10, 10, 82, 101, 115, 116, 97, - 117, 114, 97, 110, 116, 18, 12, 10, 4, 112, 97, 114, 107, 18, 4, 112, - 97, 114, 107, 18, 12, 10, 4, 119, 111, 111, 100, 18, 4, 119, 111, 111, - 100, 18, 14, 10, 5, 119, 97, 116, 101, 114, 18, 5, 119, 97, 116, 101, - 114, 18, 20, 10, 8, 98, 117, 105, 108, 100, 105, 110, 103, 18, 8, 98, - 117, 105, 108, 100, 105, 110, 103, 18, 28, 10, 12, 114, 111, 97, 100, 95, - 108, 105, 109, 105, 116, 101, 100, 18, 12, 114, 111, 97, 100, 95, 108, 105, - 109, 105, 116, 101, 100, 18, 28, 10, 12, 114, 111, 97, 100, 95, 114, 101, - 103, 117, 108, 97, 114, 18, 12, 114, 111, 97, 100, 95, 114, 101, 103, 117, - 108, 97, 114, 18, 24, 10, 10, 114, 111, 97, 100, 95, 108, 97, 114, 103, - 101, 18, 10, 114, 111, 97, 100, 95, 108, 97, 114, 103, 101, 18, 26, 10, - 11, 97, 108, 99, 111, 104, 111, 108, 95, 112, 111, 105, 18, 11, 97, 108, - 99, 111, 104, 111, 108, 95, 112, 111, 105, 18, 20, 10, 8, 99, 97, 102, - 101, 95, 112, 111, 105, 18, 8, 99, 97, 102, 101, 95, 112, 111, 105, 18, - 26, 10, 11, 101, 109, 98, 97, 115, 115, 121, 95, 112, 111, 105, 18, 11, - 101, 109, 98, 97, 115, 115, 121, 95, 112, 111, 105, 18, 20, 10, 8, 112, - 97, 114, 107, 95, 112, 111, 105, 18, 8, 112, 97, 114, 107, 95, 112, 111, - 105, 18, 32, 10, 14, 114, 101, 115, 116, 97, 117, 114, 97, 110, 116, 95, - 112, 111, 105, 18, 14, 114, 101, 115, 116, 97, 117, 114, 97, 110, 116, 95, - 112, 111, 105, 26, 160, 5, 10, 7, 100, 101, 102, 97, 117, 108, 116, 18, - 27, 10, 4, 112, 97, 114, 107, 34, 8, 8, 2, 18, 4, 0, 0, 128, - 63, 45, 255, 159, 223, 200, 66, 4, 112, 97, 114, 107, 18, 31, 10, 4, - 119, 111, 111, 100, 34, 8, 8, 2, 18, 4, 0, 0, 128, 63, 45, 255, - 102, 170, 51, 58, 8, 8, 2, 18, 4, 205, 204, 204, 61, 18, 39, 10, - 5, 119, 97, 116, 101, 114, 34, 8, 8, 2, 18, 4, 0, 0, 128, 63, - 45, 255, 233, 224, 186, 53, 255, 230, 182, 115, 66, 10, 119, 97, 116, 101, - 114, 95, 101, 116, 115, 121, 18, 51, 10, 8, 98, 117, 105, 108, 100, 105, - 110, 103, 34, 8, 8, 2, 18, 4, 0, 0, 128, 63, 45, 255, 0, 0, - 0, 58, 24, 8, 4, 18, 20, 0, 0, 80, 65, 0, 0, 0, 0, 205, - 204, 204, 61, 0, 0, 0, 0, 205, 204, 204, 61, 26, 41, 10, 12, 114, - 111, 97, 100, 95, 108, 105, 109, 105, 116, 101, 100, 29, 255, 187, 187, 187, - 34, 20, 8, 3, 18, 16, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, - 240, 65, 0, 0, 128, 63, 26, 65, 10, 12, 114, 111, 97, 100, 95, 114, - 101, 103, 117, 108, 97, 114, 29, 255, 153, 153, 153, 34, 44, 8, 3, 18, - 40, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 80, 65, 0, 0, 0, - 63, 0, 0, 128, 65, 0, 0, 0, 64, 0, 0, 160, 65, 0, 0, 0, - 66, 0, 0, 240, 65, 0, 0, 0, 66, 26, 71, 10, 10, 114, 111, 97, - 100, 95, 108, 97, 114, 103, 101, 29, 255, 102, 102, 102, 34, 52, 8, 3, - 18, 48, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 48, 65, 0, 0, - 0, 63, 0, 0, 80, 65, 0, 0, 128, 63, 0, 0, 128, 65, 0, 0, - 128, 64, 0, 0, 160, 65, 0, 0, 128, 66, 0, 0, 240, 65, 0, 0, - 128, 66, 34, 68, 10, 11, 97, 108, 99, 111, 104, 111, 108, 95, 112, 111, - 105, 29, 255, 204, 204, 204, 34, 8, 8, 2, 18, 4, 0, 0, 144, 65, - 50, 24, 8, 4, 18, 20, 0, 0, 112, 65, 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, 0, 0, 64, 63, 66, 12, 97, 108, 99, 111, - 104, 111, 108, 45, 115, 104, 111, 112, 34, 57, 10, 8, 99, 97, 102, 101, - 95, 112, 111, 105, 29, 255, 204, 204, 204, 34, 8, 8, 2, 18, 4, 0, - 0, 144, 65, 50, 24, 8, 4, 18, 20, 0, 0, 112, 65, 0, 0, 0, - 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 64, 63, 66, 4, 99, - 97, 102, 101, 34, 63, 10, 11, 101, 109, 98, 97, 115, 115, 121, 95, 112, - 111, 105, 29, 255, 204, 204, 204, 34, 8, 8, 2, 18, 4, 0, 0, 144, - 65, 50, 24, 8, 4, 18, 20, 0, 0, 112, 65, 0, 0, 0, 0, 0, - 0, 128, 63, 0, 0, 0, 0, 0, 0, 64, 63, 66, 7, 101, 109, 98, - 97, 115, 115, 121, 34, 57, 10, 8, 112, 97, 114, 107, 95, 112, 111, 105, - 29, 255, 204, 204, 204, 34, 8, 8, 2, 18, 4, 0, 0, 144, 65, 50, - 24, 8, 4, 18, 20, 0, 0, 112, 65, 0, 0, 0, 0, 0, 0, 128, - 63, 0, 0, 0, 0, 0, 0, 64, 63, 66, 4, 112, 97, 114, 107, 34, - 69, 10, 14, 114, 101, 115, 116, 97, 117, 114, 97, 110, 116, 95, 112, 111, - 105, 29, 255, 204, 204, 204, 34, 8, 8, 2, 18, 4, 0, 0, 144, 65, - 50, 24, 8, 4, 18, 20, 0, 0, 112, 65, 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, 0, 0, 64, 63, 66, 10, 114, 101, 115, 116, - 97, 117, 114, 97, 110, 116 -}; +const unsigned char resources::style[] = R"JSON({"buckets":{"water":{"datasource":"streets","layer":"water","type":"fill"},"road_large":{"datasource":"streets","layer":"road","field":"class","value":["motorway","main"],"type":"line","cap":"round","join":"round"},"road_regular":{"datasource":"streets","layer":"road","field":"class","value":"street","type":"line","cap":"round","join":"round"},"road_limited":{"datasource":"streets","layer":"road","field":"class","value":"street_limited","type":"line","cap":"round","join":"round"},"park":{"datasource":"streets","layer":"landuse","field":"class","value":"park","type":"fill"},"wood":{"datasource":"streets","layer":"landuse","field":"class","value":"wood","type":"fill"},"school":{"datasource":"streets","layer":"landuse","field":"class","value":"school","type":"fill"},"cemetery":{"datasource":"streets","layer":"landuse","field":"class","value":"cemetery","type":"fill"},"industrial":{"datasource":"streets","layer":"landuse","field":"class","value":"industrial","type":"fill"},"building":{"datasource":"streets","layer":"building","type":"fill"},"alcohol_poi":{"datasource":"streets","layer":"poi_label","field":"type","value":["Alcohol"],"type":"point"},"cafe_poi":{"datasource":"streets","layer":"poi_label","field":"type","value":["Cafe"],"type":"point"},"embassy_poi":{"datasource":"streets","layer":"poi_label","field":"type","value":["Embassy"],"type":"point"},"park_poi":{"datasource":"streets","layer":"poi_label","field":"type","value":["Park"],"type":"point"},"restaurant_poi":{"datasource":"streets","layer":"poi_label","field":"type","value":["Restaurant"],"type":"point"}},"sprite":"img/maki-sprite","structure":[{"name":"park","bucket":"park"},{"name":"wood","bucket":"wood"},{"name":"water","bucket":"water"},{"name":"building","bucket":"building"},{"name":"road_limited","bucket":"road_limited"},{"name":"road_regular","bucket":"road_regular"},{"name":"road_large","bucket":"road_large"},{"name":"alcohol_poi","bucket":"alcohol_poi"},{"name":"cafe_poi","bucket":"cafe_poi"},{"name":"embassy_poi","bucket":"embassy_poi"},{"name":"park_poi","bucket":"park_poi"},{"name":"restaurant_poi","bucket":"restaurant_poi"}],"classes":[{"name":"default","layers":{"background":{"type":"background","color":"#FFFFFF"},"park":{"type":"fill","color":"#c8df9f","antialias":true,"image":"park"},"wood":{"type":"fill","color":"#33AA66","antialias":true,"opacity":0.1},"water":{"type":"fill","color":"#bae0e9","stroke":"#73b6e6","antialias":true,"image":"water_etsy"},"building":{"type":"fill","color":"#000000","antialias":true,"opacity":["linear",13,0,0.1,0,0.1]},"road_limited":{"type":"line","color":"#BBBBBB","width":["stops",{"z":0,"val":1},{"z":30,"val":1}]},"road_regular":{"type":"line","color":"#999999","width":["stops",{"z":0,"val":0.5},{"z":13,"val":0.5},{"z":16,"val":2},{"z":20,"val":32},{"z":30,"val":32}]},"road_large":{"type":"line","color":"#666666","width":["stops",{"z":0,"val":0.5},{"z":11,"val":0.5},{"z":13,"val":1},{"z":16,"val":4},{"z":20,"val":64},{"z":30,"val":64}]},"alcohol_poi":{"type":"point","color":"#cccccc","size":18,"image":"alcohol-shop","opacity":["linear",15,0,1,0,0.75]},"cafe_poi":{"type":"point","color":"#cccccc","size":18,"image":"cafe","opacity":["linear",15,0,1,0,0.75]},"embassy_poi":{"type":"point","color":"#cccccc","size":18,"image":"embassy","opacity":["linear",15,0,1,0,0.75]},"park_poi":{"type":"point","color":"#cccccc","size":18,"image":"park","opacity":["linear",15,0,1,0,0.75]},"restaurant_poi":{"type":"point","color":"#cccccc","size":18,"image":"restaurant","opacity":["linear",15,0,1,0,0.75]}}}]})JSON"; const unsigned long resources::style_size = sizeof(resources::style); diff --git a/src/style/style.cpp b/src/style/style.cpp index eeeb37e47..a17fb8689 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1,6 +1,7 @@ #include +#include -// #include +#include using namespace llmr; @@ -15,215 +16,6 @@ void Style::reset() { computed.points.clear(); } -void Style::load(const uint8_t *const data, size_t bytes) { - pbf style(data, bytes); - - while (style.next()) { - if (style.tag == 1) { // bucket - buckets.insert(parseBucket(style.message())); - } else if (style.tag == 2) { // structure - layers.push_back(parseLayer(style.message())); - } else if (style.tag == 3) { // class - classes.insert(parseClass(style.message())); - } else { - style.skip(); - } - } -} - -std::pair Style::parseBucket(pbf data) { - BucketDescription bucket; - std::string name; - - while (data.next()) { - if (data.tag == 1) { // name - name = data.string(); - } else if (data.tag == 2) { // type - bucket.type = (BucketType)data.varint(); - } else if (data.tag == 3) { // source_name - bucket.source_name = data.string(); - } else if (data.tag == 4) { // source_layer - bucket.source_layer = data.string(); - } else if (data.tag == 5) { // source_field - bucket.source_field = data.string(); - } else if (data.tag == 6) { // source_value - bucket.source_value.emplace_back(parseValue(data.message())); - } else if (data.tag == 7) { // cap - bucket.geometry.cap = (CapType)data.varint(); - } else if (data.tag == 8) { // join - bucket.geometry.join = (JoinType)data.varint(); - } else if (data.tag == 9) { // font - bucket.geometry.font = data.string(); - } else if (data.tag == 10) { // font_size - bucket.geometry.font_size = data.float32(); - } else { - data.skip(); - } - } - - return { name, std::forward(bucket) }; -} - -LayerDescription Style::parseLayer(pbf data) { - LayerDescription layer; - - while (data.next()) { - if (data.tag == 1) { // name - layer.name = data.string(); - } else if (data.tag == 2) { // bucket_name - layer.bucket_name = data.string(); - } else if (data.tag == 3) { // child_layer - layer.child_layer.emplace_back(parseLayer(data.message())); - } else { - data.skip(); - } - } - - return layer; -} - - -std::pair Style::parseClass(pbf data) { - ClassDescription klass; - std::string name; - - while (data.next()) { - if (data.tag == 1) { // name - name = data.string(); - } else if (data.tag == 2) { // fill style - klass.fill.insert(parseFillClass(data.message())); - } else if (data.tag == 3) { // line style - klass.line.insert(parseLineClass(data.message())); - } else if (data.tag == 4) { // point style - klass.point.insert(parsePointClass(data.message())); - } else { - data.skip(); - } - } - - return { name, klass }; -} - -std::pair Style::parseFillClass(pbf data) { - FillClass fill; - std::string name; - - while (data.next()) { - if (data.tag == 1) { // name - name = data.string(); - } else if (data.tag == 2) { // hidden - fill.hidden = parseProperty(data.message()); - } else if (data.tag == 3) { // winding - fill.winding = (Winding)data.varint(); - } else if (data.tag == 4) { // antialias - fill.antialias = parseProperty(data.message()); - } else if (data.tag == 5) { // fill_color - fill.fill_color = parseColor(data); - if (fill.stroke_color[3] == std::numeric_limits::infinity()) { - fill.stroke_color = fill.fill_color; - } - } else if (data.tag == 6) { // stroke_color - fill.stroke_color = parseColor(data); - } else if (data.tag == 7) { // opacity - fill.opacity = parseProperty(data.message()); - } else if (data.tag == 8) { // image - fill.image = data.string(); - } else { - data.skip(); - } - } - - return { name, fill }; -} - - -std::pair Style::parseLineClass(pbf data) { - LineClass stroke; - std::string name; - - while (data.next()) { - if (data.tag == 1) { // name - name = data.string(); - } else if (data.tag == 2) { // hidden - stroke.hidden = parseProperty(data.message()); - } else if (data.tag == 3) { // color - stroke.color = parseColor(data); - } else if (data.tag == 4) { // width - stroke.width = parseProperty(data.message()); - } else if (data.tag == 5) { // offset - stroke.offset = parseProperty(data.message()); - } else if (data.tag == 6) { // opacity - stroke.opacity = parseProperty(data.message()); - } else { - data.skip(); - } - } - - return { name, stroke }; -} - -std::pair Style::parsePointClass(pbf data) { - PointClass point; - std::string name; - - while (data.next()) { - if (data.tag == 1) { // name - name = data.string(); - } else if (data.tag == 2) { // hidden - point.hidden = parseProperty(data.message()); - } else if (data.tag == 3) { // color - point.color = parseColor(data); - } else if (data.tag == 4) { // size - point.size = parseProperty(data.message()); - } else if (data.tag == 6) { // opacity - point.opacity = parseProperty(data.message()); - } else if (data.tag == 8) { // image - point.image = data.string(); - } else { - data.skip(); - } - } - - return { name, point }; -} - -Color Style::parseColor(pbf& data) { - uint32_t rgba = data.fixed(); - return {{ - (float)((rgba >> 24) & 0xFF) / 0xFF, - (float)((rgba >> 16) & 0xFF) / 0xFF, - (float)((rgba >> 8) & 0xFF) / 0xFF, - (float)((rgba >> 0) & 0xFF) / 0xFF - } - }; -} - -template FunctionProperty Style::parseProperty(pbf data) { - FunctionProperty property; - - while (data.next()) { - if (data.tag == 1) { // function - switch ((Property)data.varint()) { - case Property::Null: property.function = &functions::null; break; - case Property::Constant: property.function = &functions::constant; break; - case Property::Stops: property.function = &functions::stops; break; - case Property::Linear: property.function = &functions::linear; break; - default: property.function = &functions::null; break; - } - } else if (data.tag == 2) { // value - // read a packed float32 - pbf floats = data.message(); - while (floats) { - property.values.push_back(floats.float32()); - } - } else { - data.skip(); - } - } - - return property; -} - void Style::cascade(float z) { reset(); @@ -285,7 +77,7 @@ void Style::cascade(float z) { } } -/* + void loadBucketsJSON(const rapidjson::Value& value, std::map& buckets); BucketDescription loadBucketJSON(const rapidjson::Value& value); @@ -296,11 +88,26 @@ std::pair loadClassDescriptionJSON(const rapidjso void loadClassJSON(const std::string& name, const rapidjson::Value& value, ClassDescription& class_desc); FillClass loadFillClassJSON(const rapidjson::Value& value); LineClass loadLineClassJSON(const rapidjson::Value& value); +PointClass loadPointClassJSON(const rapidjson::Value& value); +BackgroundClass loadBackgroundClassJSON(const rapidjson::Value& value); Value loadValueJSON(const rapidjson::Value& value); -void Style::loadJSON(const std::string& data) { +void Style::loadJSON(const uint8_t *const data, size_t bytes) { rapidjson::Document document; - document.Parse<0>(data.c_str()); + + if (bytes <= 0) { + return; + } + + if (data[bytes - 1] != 0) { + throw exception("style JSON string is not 0-terminated"); + } + + document.Parse<0>((const char *const)data); + + buckets.clear(); + layers.clear(); + classes.clear(); if (document.IsObject()) { if (document.HasMember("buckets")) { @@ -315,7 +122,7 @@ void Style::loadJSON(const std::string& data) { loadClassesJSON(document["classes"], classes); } } else { - fprintf(stderr, "stylesheet root must be an object\n"); + throw Style::exception("stylesheet root must be an object"); } } @@ -323,10 +130,10 @@ void loadBucketsJSON(const rapidjson::Value& value, std::mapname.GetString(), loadBucketJSON(itr->value)); + buckets.emplace(itr->name.GetString(), std::forward(loadBucketJSON(itr->value))); } } else { - fprintf(stderr, "buckets must be an object\n"); + throw Style::exception("buckets must be an object"); } } @@ -342,25 +149,25 @@ BucketDescription loadBucketJSON(const rapidjson::Value& value) { if (value.IsString()) { bucket.type = bucketType({ value.GetString(), value.GetStringLength() }); } else { - fprintf(stderr, "bucket type must be a string\n"); + throw Style::exception("bucket type must be a string"); } } else if (name == "datasource") { if (value.IsString()) { bucket.source_name = { value.GetString(), value.GetStringLength() }; } else { - fprintf(stderr, "datasource name must be a string\n"); + throw Style::exception("datasource name must be a string"); } } else if (name == "layer") { if (value.IsString()) { bucket.source_layer = { value.GetString(), value.GetStringLength() }; } else { - fprintf(stderr, "layer name must be a string\n"); + throw Style::exception("layer name must be a string"); } } else if (name == "field") { if (value.IsString()) { bucket.source_field = { value.GetString(), value.GetStringLength() }; } else { - fprintf(stderr, "field name must be a string\n"); + throw Style::exception("field name must be a string"); } } else if (name == "value") { if (value.IsArray()) { @@ -374,25 +181,37 @@ BucketDescription loadBucketJSON(const rapidjson::Value& value) { if (value.IsString()) { bucket.geometry.cap = capType({ value.GetString(), value.GetStringLength() }); } else { - fprintf(stderr, "cap type must be a string\n"); + throw Style::exception("cap type must be a string"); } } else if (name == "join") { if (value.IsString()) { bucket.geometry.join = joinType({ value.GetString(), value.GetStringLength() }); } else { - fprintf(stderr, "join type must be a string\n"); + throw Style::exception("join type must be a string"); } } else if (name == "font") { if (value.IsString()) { bucket.geometry.font = { value.GetString(), value.GetStringLength() }; } else { - fprintf(stderr, "font stack must be a string\n"); + throw Style::exception("font stack must be a string"); } } else if (name == "fontSize") { if (value.IsNumber()) { bucket.geometry.font_size = value.GetDouble(); } else { - fprintf(stderr, "font size must be a number\n"); + throw Style::exception("font size must be a number"); + } + } else if (name == "miterLimit") { + if (value.IsNumber()) { + bucket.geometry.miter_limit = value.GetDouble(); + } else { + throw Style::exception("miter limit must be a number"); + } + } else if (name == "roundLimit") { + if (value.IsNumber()) { + bucket.geometry.round_limit = value.GetDouble(); + } else { + throw Style::exception("round limit must be a number"); } } } @@ -400,16 +219,14 @@ BucketDescription loadBucketJSON(const rapidjson::Value& value) { return bucket; } - void loadLayersJSON(const rapidjson::Value& value, std::vector& layers) { if (value.IsArray()) { for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { layers.push_back(loadLayerJSON(value[i])); } } else { - fprintf(stderr, "structure must be an array\n"); + throw Style::exception("structure must be an array"); } - } LayerDescription loadLayerJSON(const rapidjson::Value& value) { @@ -421,10 +238,10 @@ LayerDescription loadLayerJSON(const rapidjson::Value& value) { if (name.IsString()) { layer.name = { name.GetString(), name.GetStringLength() }; } else { - fprintf(stderr, "structure element name must be a string\n"); + throw Style::exception("structure element name must be a string"); } } else { - fprintf(stderr, "structure element must have a name\n"); + throw Style::exception("structure element must have a name"); } if (value.HasMember("bucket")) { @@ -432,28 +249,27 @@ LayerDescription loadLayerJSON(const rapidjson::Value& value) { if (bucket.IsString()) { layer.bucket_name = { bucket.GetString(), bucket.GetStringLength() }; } else { - fprintf(stderr, "structure element bucket must be a string\n"); + throw Style::exception("structure element bucket must be a string"); } } else if (value.HasMember("layers")) { loadLayersJSON(value["layers"], layer.child_layer); } else { - fprintf(stderr, "structure element must have either a bucket name or child layers\n"); + throw Style::exception("structure element must have either a bucket name or child layers"); } } else { - fprintf(stderr, "structure element must be an object\n"); + throw Style::exception("structure element must be an object"); } return layer; } - void loadClassesJSON(const rapidjson::Value& value, std::map& classes) { if (value.IsArray()) { for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - classes.insert(loadClassDescriptionJSON(value[i])); + classes.insert(std::forward>(loadClassDescriptionJSON(value[i]))); } } else { - fprintf(stderr, "classes must be an array\n"); + throw Style::exception("classes must be an array"); } } @@ -467,10 +283,10 @@ std::pair loadClassDescriptionJSON(const rapidjso if (name.IsString()) { klass_name = { name.GetString(), name.GetStringLength() }; } else { - fprintf(stderr, "class name must be a string\n"); + throw Style::exception("class name must be a string"); } } else { - fprintf(stderr, "class must have a name\n"); + throw Style::exception("class must have a name"); } if (value.HasMember("layers")) { @@ -485,14 +301,14 @@ std::pair loadClassDescriptionJSON(const rapidjso loadClassJSON(name, itr->value, klass); } } else { - fprintf(stderr, "class layer styles must be an object\n"); + throw Style::exception("class layer styles must be an object"); } } else { - fprintf(stderr, "class must have layer styles\n"); + throw Style::exception("class must have layer styles"); } } - return { klass_name, klass }; + return { klass_name, std::forward(klass) }; } void loadClassJSON(const std::string& name, const rapidjson::Value& value, ClassDescription& class_desc) { @@ -502,40 +318,255 @@ void loadClassJSON(const std::string& name, const rapidjson::Value& value, Class if (type.IsString()) { std::string type_name = { type.GetString(), type.GetStringLength() }; if (type_name == "fill") { - class_desc.fill.insert({ type_name, loadFillClassJSON(value) }); + class_desc.fill.insert({ name, std::forward(loadFillClassJSON(value)) }); } else if (type_name == "line") { - class_desc.line.insert({ type_name, loadLineClassJSON(value) }); + class_desc.line.insert({ name, std::forward(loadLineClassJSON(value)) }); + } else if (type_name == "point") { + class_desc.point.insert({ name, std::forward(loadPointClassJSON(value)) }); + } else if (type_name == "background") { + class_desc.background = loadBackgroundClassJSON(value); } else { - // TODO: + throw Style::exception("unkonwn class type name"); } } else { - fprintf(stderr, "style class type must be a string\n"); + throw Style::exception("style class type must be a string"); } } else { - fprintf(stderr, "style class must specify a type\n"); + throw Style::exception("style class must specify a type"); } } else { - fprintf(stderr, "style class must be an object\n"); + throw Style::exception("style class must be an object"); } } +bool parseBoolean(const rapidjson::Value& value) { + if (!value.IsBool()) { + throw Style::exception("boolean value must be a boolean"); + } + + return value.GetBool(); +} + +std::string parseString(const rapidjson::Value& value) { + if (!value.IsString()) { + throw Style::exception("string value must be a string"); + } + + return { value.GetString(), value.GetStringLength() }; +} + +Color parseColor(const rapidjson::Value& value) { + if (!value.IsString()) { + throw Style::exception("color value must be a string"); + } + + llmr::util::CSSColor css_color = llmr::util::parseCSSColor({ + value.GetString(), + value.GetStringLength() + }); + + return {{ + (float)css_color.r / 255, + (float)css_color.g / 255, + (float)css_color.b / 255, + css_color.a + } + }; +} + +template +typename FunctionProperty::fn parseFunctionType(const rapidjson::Value& type) { + if (type.IsString()) { + std::string t { type.GetString(), type.GetStringLength() }; + if (t == "constant") { + return &functions::constant; + } else if (t == "linear") { + return &functions::linear; + } else if (t == "stops") { + return &functions::stops; + } else { + throw Style::exception("unknown function type"); + } + } else { + throw Style::exception("function type must be a string"); + } +} + +FunctionProperty parseFloatFunction(const rapidjson::Value& value) { + FunctionProperty property; + + if (value.IsArray()) { + if (value.Size() < 1) { + throw Style::exception("value function does not have arguments"); + } + + property.function = parseFunctionType(value[(rapidjson::SizeType)0]); + for (rapidjson::SizeType i = 1; i < value.Size(); ++i) { + const rapidjson::Value& stop = value[i]; + if (stop.IsObject()) { + if (!stop.HasMember("z")) { + throw Style::exception("stop must have zoom level specification"); + } + const rapidjson::Value& z = stop["z"]; + if (!z.IsNumber()) { + throw Style::exception("zoom level in stops must be a number"); + } + property.values.push_back(z.GetDouble()); + + if (!stop.HasMember("val")) { + throw Style::exception("stop must have value specification"); + } + const rapidjson::Value& val = stop["val"]; + if (!val.IsNumber()) { + throw Style::exception("value in stops must be a number"); + } + property.values.push_back(val.GetDouble()); + } else if (stop.IsNumber()) { + property.values.push_back(stop.GetDouble()); + } else { + throw Style::exception("stop must be a number"); + } + } + } else if (value.IsNumber()) { + property.function = &functions::constant; + property.values.push_back(value.GetDouble()); + } + + return property; +} + +FunctionProperty parseBoolFunction(const rapidjson::Value& value) { + FunctionProperty property; + + if (value.IsArray()) { + if (value.Size() < 1) { + throw Style::exception("value function does not have arguments"); + } + + property.function = parseFunctionType(value[(rapidjson::SizeType)0]); + for (rapidjson::SizeType i = 1; i < value.Size(); ++i) { + const rapidjson::Value& stop = value[i]; + if (stop.IsObject()) { + if (!stop.HasMember("z")) { + throw Style::exception("stop must have zoom level specification"); + } + const rapidjson::Value& z = stop["z"]; + if (!z.IsBool()) { + throw Style::exception("zoom level in stops must be a number"); + } + property.values.push_back(z.GetBool()); + + if (!stop.HasMember("val")) { + throw Style::exception("stop must have value specification"); + } + const rapidjson::Value& val = stop["val"]; + if (!val.IsBool()) { + throw Style::exception("value in stops must be a number"); + } + property.values.push_back(val.GetBool()); + } else if (stop.IsBool()) { + property.values.push_back(stop.GetBool()); + } else { + throw Style::exception("stop must be a number"); + } + } + } else if (value.IsBool()) { + property.function = &functions::constant; + property.values.push_back(value.GetBool()); + } + + return property; +} + FillClass loadFillClassJSON(const rapidjson::Value& value) { FillClass klass; if (value.HasMember("hidden")) { - const rapidjson::Value& hidden = value["hidden"]; - // TODO... + klass.hidden = parseBoolFunction(value["hidden"]); + } + if (value.HasMember("color")) { + klass.fill_color = parseColor(value["color"]); + } + + if (value.HasMember("stroke")) { + klass.stroke_color = parseColor(value["stroke"]); + } else { + klass.stroke_color = klass.fill_color; + } + + if (value.HasMember("antialias")) { + klass.antialias = parseBoolean(value["antialias"]); + } + + if (value.HasMember("image")) { + klass.image = parseString(value["image"]); + } + + if (value.HasMember("opacity")) { + klass.opacity = parseFloatFunction(value["opacity"]); } return klass; } LineClass loadLineClassJSON(const rapidjson::Value& value) { - FillClass klass; + LineClass klass; + + if (value.HasMember("hidden")) { + klass.hidden = parseBoolFunction(value["hidden"]); + } + + if (value.HasMember("color")) { + klass.color = parseColor(value["color"]); + } + + if (value.HasMember("width")) { + klass.width = parseFloatFunction(value["width"]); + } + + if (value.HasMember("opacity")) { + klass.opacity = parseFloatFunction(value["opacity"]); + } + + return klass; } +PointClass loadPointClassJSON(const rapidjson::Value& value) { + PointClass klass; + if (value.HasMember("hidden")) { + klass.hidden = parseBoolFunction(value["hidden"]); + } + + if (value.HasMember("color")) { + klass.color = parseColor(value["color"]); + } + + if (value.HasMember("opacity")) { + klass.opacity = parseFloatFunction(value["opacity"]); + } + + if (value.HasMember("image")) { + klass.image = parseString(value["image"]); + } + + if (value.HasMember("size")) { + klass.size = parseFloatFunction(value["size"]); + } + + return klass; +} + +BackgroundClass loadBackgroundClassJSON(const rapidjson::Value& value) { + BackgroundClass klass; + + if (value.HasMember("color")) { + klass.fill_color = parseColor(value["color"]); + } + + return klass; +} Value loadValueJSON(const rapidjson::Value& value) { switch (value.GetType()) { @@ -556,9 +587,7 @@ Value loadValueJSON(const rapidjson::Value& value) { case rapidjson::kObjectType: case rapidjson::kArrayType: - fprintf(stderr, "value cannot be an object or array\n"); + throw Style::exception("value cannot be an object or array"); return false; } } - -*/