parse the json stylesheet
This commit is contained in:
@@ -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 <llmr/style/resources.hpp>\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);
|
||||
|
||||
@@ -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 <llmr/style/resources.hpp>\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);
|
||||
|
||||
@@ -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());
|
||||
10
bin/style.js
10
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",
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace llmr {
|
||||
|
||||
class ClassDescription {
|
||||
public:
|
||||
BackgroundClass background;
|
||||
std::map<std::string, FillClass> fill;
|
||||
std::map<std::string, LineClass> line;
|
||||
std::map<std::string, PointClass> point;
|
||||
|
||||
@@ -112,6 +112,10 @@ struct FillProperties {
|
||||
std::string image;
|
||||
};
|
||||
|
||||
struct BackgroundClass {
|
||||
Color fill_color = {{ 0, 0, 0, 0 }};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
12
llmr.gyp
12
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'
|
||||
|
||||
Binary file not shown.
@@ -30,8 +30,7 @@ void Map::setup(float pixelRatio) {
|
||||
style.sprite = std::make_shared<Sprite>();
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <llmr/style/style.hpp>
|
||||
#include <llmr/util/color.hpp>
|
||||
|
||||
// #include <rapidjson/document.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
|
||||
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<std::string, BucketDescription> 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<BucketDescription>(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<std::string, ClassDescription> 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<std::string, FillClass> 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<bool>(data.message());
|
||||
} else if (data.tag == 3) { // winding
|
||||
fill.winding = (Winding)data.varint();
|
||||
} else if (data.tag == 4) { // antialias
|
||||
fill.antialias = parseProperty<bool>(data.message());
|
||||
} else if (data.tag == 5) { // fill_color
|
||||
fill.fill_color = parseColor(data);
|
||||
if (fill.stroke_color[3] == std::numeric_limits<float>::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<float>(data.message());
|
||||
} else if (data.tag == 8) { // image
|
||||
fill.image = data.string();
|
||||
} else {
|
||||
data.skip();
|
||||
}
|
||||
}
|
||||
|
||||
return { name, fill };
|
||||
}
|
||||
|
||||
|
||||
std::pair<std::string, LineClass> 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<bool>(data.message());
|
||||
} else if (data.tag == 3) { // color
|
||||
stroke.color = parseColor(data);
|
||||
} else if (data.tag == 4) { // width
|
||||
stroke.width = parseProperty<float>(data.message());
|
||||
} else if (data.tag == 5) { // offset
|
||||
stroke.offset = parseProperty<float>(data.message());
|
||||
} else if (data.tag == 6) { // opacity
|
||||
stroke.opacity = parseProperty<float>(data.message());
|
||||
} else {
|
||||
data.skip();
|
||||
}
|
||||
}
|
||||
|
||||
return { name, stroke };
|
||||
}
|
||||
|
||||
std::pair<std::string, PointClass> 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<bool>(data.message());
|
||||
} else if (data.tag == 3) { // color
|
||||
point.color = parseColor(data);
|
||||
} else if (data.tag == 4) { // size
|
||||
point.size = parseProperty<float>(data.message());
|
||||
} else if (data.tag == 6) { // opacity
|
||||
point.opacity = parseProperty<float>(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<uint32_t, 4>();
|
||||
return {{
|
||||
(float)((rgba >> 24) & 0xFF) / 0xFF,
|
||||
(float)((rgba >> 16) & 0xFF) / 0xFF,
|
||||
(float)((rgba >> 8) & 0xFF) / 0xFF,
|
||||
(float)((rgba >> 0) & 0xFF) / 0xFF
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T> FunctionProperty<T> Style::parseProperty(pbf data) {
|
||||
FunctionProperty<T> 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<std::string, BucketDescription>& buckets);
|
||||
BucketDescription loadBucketJSON(const rapidjson::Value& value);
|
||||
@@ -296,11 +88,26 @@ std::pair<std::string, ClassDescription> 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::map<std::string, Bucket
|
||||
if (value.IsObject()) {
|
||||
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
|
||||
for (; itr != value.MemberEnd(); ++itr) {
|
||||
buckets.emplace(itr->name.GetString(), loadBucketJSON(itr->value));
|
||||
buckets.emplace(itr->name.GetString(), std::forward<BucketDescription>(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<LayerDescription>& 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<std::string, ClassDescription>& classes) {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
classes.insert(loadClassDescriptionJSON(value[i]));
|
||||
classes.insert(std::forward<std::pair<std::string, ClassDescription>>(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<std::string, ClassDescription> 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<std::string, ClassDescription> 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<ClassDescription>(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<FillClass>(loadFillClassJSON(value)) });
|
||||
} else if (type_name == "line") {
|
||||
class_desc.line.insert({ type_name, loadLineClassJSON(value) });
|
||||
class_desc.line.insert({ name, std::forward<LineClass>(loadLineClassJSON(value)) });
|
||||
} else if (type_name == "point") {
|
||||
class_desc.point.insert({ name, std::forward<PointClass>(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 T>
|
||||
typename FunctionProperty<T>::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<float> parseFloatFunction(const rapidjson::Value& value) {
|
||||
FunctionProperty<float> property;
|
||||
|
||||
if (value.IsArray()) {
|
||||
if (value.Size() < 1) {
|
||||
throw Style::exception("value function does not have arguments");
|
||||
}
|
||||
|
||||
property.function = parseFunctionType<float>(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<bool> parseBoolFunction(const rapidjson::Value& value) {
|
||||
FunctionProperty<bool> property;
|
||||
|
||||
if (value.IsArray()) {
|
||||
if (value.Size() < 1) {
|
||||
throw Style::exception("value function does not have arguments");
|
||||
}
|
||||
|
||||
property.function = parseFunctionType<bool>(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;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user