This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository node-osmium.
commit 38391dbafd15a97c071294c3269db47740af9df6 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Fri Mar 6 15:16:44 2015 +0100 Imported Upstream version 0.3.0 --- .npmignore | 10 + Makefile | 1 + binding.gyp | 3 + demo/converter/README.md | 14 + demo/converter/index.js | 117 +++++++++ demo/converter/package.json | 7 + demo/converter/roads-from-buffer.js | 94 +++++++ demo/converter/roads.js | 92 +++++++ demo/count/README.md | 8 + demo/count/index.js | 35 +++ demo/count/package.json | 6 + demo/histstat/README.md | 13 + demo/histstat/index.js | 46 ++++ demo/histstat/package.json | 6 + demo/multipolygon/README.md | 12 + demo/multipolygon/index.js | 41 +++ demo/multipolygon/package.json | 7 + doc/tutorial.md | 111 ++++++++ lib/osmium.js | 291 +++++++++++++++++++++ package.json | 2 +- src/apply.cpp | 13 +- src/apply.hpp | 8 +- src/buffer_wrap.cpp | 71 +++-- src/buffer_wrap.hpp | 29 +- src/file_wrap.cpp | 9 +- src/file_wrap.hpp | 19 +- src/handler.cpp | 27 +- src/handler.hpp | 12 +- src/{apply.hpp => include_v8.hpp} | 13 +- src/location_handler_wrap.cpp | 6 +- src/location_handler_wrap.hpp | 18 +- src/multipolygon_collector_wrap.cpp | 97 +++++++ src/multipolygon_collector_wrap.hpp | 46 ++++ src/multipolygon_handler_wrap.cpp | 33 +++ src/multipolygon_handler_wrap.hpp | 42 +++ src/node_osmium.cpp | 75 +++++- src/node_osmium.hpp | 45 ++++ src/osm_area_wrap.cpp | 71 +++++ src/osm_area_wrap.hpp | 52 ++++ src/osm_changeset_wrap.cpp | 15 +- src/osm_changeset_wrap.hpp | 17 +- src/osm_entity_wrap.cpp | 6 +- src/osm_entity_wrap.hpp | 14 +- src/osm_node_wrap.cpp | 29 +- src/osm_node_wrap.hpp | 16 +- src/osm_object_wrap.cpp | 14 +- src/osm_object_wrap.hpp | 12 +- src/osm_relation_wrap.cpp | 24 +- src/osm_relation_wrap.hpp | 18 +- src/osm_way_wrap.cpp | 21 +- src/osm_way_wrap.hpp | 16 +- src/reader_wrap.cpp | 50 ++-- src/reader_wrap.hpp | 25 +- src/utils.cpp | 5 +- src/utils.hpp | 20 +- test/changesets.test.js | 1 + test/data/coordinates-problems.osm | 6 + ...reation.test.js => osm-object-creation.test.js} | 0 test/osm-objects.test.js | 27 ++ test/reader.test.js | 18 ++ 60 files changed, 1713 insertions(+), 243 deletions(-) diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..f6a4e2e --- /dev/null +++ b/.npmignore @@ -0,0 +1,10 @@ +.gitignore +.gitmodules +.npmignore +.travis.yml +Makefile +build +demo +node_modules +scripts +test diff --git a/Makefile b/Makefile index f5e5d06..5ee8736 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ INCLUDES_REPORT_FILES := $(subst src,check_reports,$(INCLUDE_FILES:.hpp=.compile DEMOS := $(shell find demo -mindepth 1 -maxdepth 1 -type d) all: build +.PHONY: all build ./node_modules: npm install --build-from-source diff --git a/binding.gyp b/binding.gyp index fd4eb2b..6dae20d 100644 --- a/binding.gyp +++ b/binding.gyp @@ -13,7 +13,10 @@ "src/file_wrap.cpp", "src/handler.cpp", "src/location_handler_wrap.cpp", + "src/multipolygon_collector_wrap.cpp", + "src/multipolygon_handler_wrap.cpp", "src/node_osmium.cpp", + "src/osm_area_wrap.cpp", "src/osm_changeset_wrap.cpp", "src/osm_entity_wrap.cpp", "src/osm_node_wrap.cpp", diff --git a/demo/converter/README.md b/demo/converter/README.md new file mode 100644 index 0000000..9f7af87 --- /dev/null +++ b/demo/converter/README.md @@ -0,0 +1,14 @@ +# converter + +Convert OSM file into spatialite database. + +## Install + + npm install + +## Usage + + ./index.js ../../test/data/winthrop.osm winthrop.db + +You will get a spatialite database with several tables. + diff --git a/demo/converter/index.js b/demo/converter/index.js new file mode 100755 index 0000000..3121e75 --- /dev/null +++ b/demo/converter/index.js @@ -0,0 +1,117 @@ +#!/usr/bin/env node + +var osmium = require('../../'); + +if (process.argv.length != 4) { + console.log("Usage: " + process.argv[0] + ' ' + process.argv[1] + " OSMFILE DBFILE"); + process.exit(1); +} + +var input_file = process.argv[2]; +var output_file = process.argv[3]; + +var converter = new osmium.Converter({ output: output_file, show_layers: true }); + +converter.create_layer('natural_pois', 'point'). + with_attribute('osm_id', 'string'). + with_attribute('type', 'string'). + with_attribute('name', 'string'); + +converter.create_layer('roads', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'). + with_attribute('ref', 'string'). + with_attribute('oneway', 'integer'). + with_attribute('maxspeed', 'integer'); + +converter.create_layer('cycleways', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('name', 'string'); + +converter.create_layer('railways', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('name', 'string'); + +converter.create_layer('waterways', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'); + +converter.create_layer('boundaries', 'multipolygon'). + with_attribute('osm_id', 'integer'). + with_attribute('level', 'integer'). + with_attribute('name', 'string'); + +converter.create_layer('landuse', 'multipolygon'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'); + +converter.create_layer('water', 'multipolygon'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'); + +// ---- rules ---- + +converter.add_nodes(). + matching('natural', 'tree|peak|spring'). + to_layer('natural_pois'). + with_attribute('type', 'natural'). + with_attribute('name'); + +converter.add_ways(). + matching('waterway', 'stream|river|ditch|canal|drain'). + to_layer('waterways'). + with_attribute('type', 'waterway'). + with_attribute('name'); + +converter.add_ways(). + matching('highway', /^(motorway|trunk|primary|secondary)(_link)?$/). + to_layer('roads'). + with_attribute('type', 'highway'). + with_attribute('ref'). + with_attribute('name'). + with_attribute('oneway', function(tags) { + var o = tags['oneway']; + if (o == 'yes' || o == 'true' || o == '1') { + return 1; + } else if (o == "-1") { + return -1; + } else { + return 0; + } + }). + with_attribute('maxspeed') + +converter.add_ways(). + matching('highway', 'cycleway'). + to_layer('cycleways'). + with_attribute('name'); + +converter.add_ways(). + matching('railway', 'rail'). + to_layer('railways'). + with_attribute('name'); + +converter.add_areas(). + matching('boundary', 'administrative'). + to_layer('boundaries'). + with_attribute('level', 'admin_level'). + with_attribute('name'); + +converter.add_areas(). + matching('landuse', 'forest|grass|residential|farm|meadow|farmland|industrial|farmyard|cemetery|commercial|quarry|orchard|vineyard|allotments|retail|construction|recreation_ground|village_green'). + to_layer('landuse'). + with_attribute('type', 'landuse'). + with_attribute('name'); + +converter.add_areas(). + matching('natural', 'water'). + to_layer('water'). + with_attribute('type', 'natural'). + with_attribute('name'); + +converter.convert(input_file); + diff --git a/demo/converter/package.json b/demo/converter/package.json new file mode 100644 index 0000000..1339b30 --- /dev/null +++ b/demo/converter/package.json @@ -0,0 +1,7 @@ +{ + "name": "test", + "version": "0.0.0", + "dependencies": { + "spatialite": "*" + } +} diff --git a/demo/converter/roads-from-buffer.js b/demo/converter/roads-from-buffer.js new file mode 100755 index 0000000..66adad4 --- /dev/null +++ b/demo/converter/roads-from-buffer.js @@ -0,0 +1,94 @@ +#!/usr/bin/env node + +var osmium = require('../../'); + +if (process.argv.length != 4) { + console.log("Usage: " + process.argv[0] + ' ' + process.argv[1] + " OSMFILE DBFILE"); + process.exit(1); +} + +var input_file = process.argv[2]; +var output_file = process.argv[3]; + +var converter = new osmium.Converter({ output: output_file, show_layers: true }); + +// ---- layers ---- + +converter.create_layer('turning_circles'). + with_attribute('osm_id', 'string'); + +converter.create_layer('traffic_signals'). + with_attribute('osm_id', 'string'); + +converter.create_layer('major_roads', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'). + with_attribute('ref', 'string'). + with_attribute('oneway', 'integer'). + with_attribute('maxspeed', 'integer'); + +converter.create_layer('minor_roads', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'). + with_attribute('ref', 'string'). + with_attribute('oneway', 'integer'). + with_attribute('maxspeed', 'integer'); + +converter.create_layer('plazas', 'multipolygon'). + with_attribute('osm_id', 'integer'). + with_attribute('name', 'string'); + + +// ---- rules ---- + +converter.add_nodes(). + matching('highway', 'traffic_signals'). + to_layer('traffic_signals'); + +converter.add_nodes(). + matching('highway', 'turning_circle'). + to_layer('turning_circles'); + +function convert_oneway(tags) { + var o = tags['oneway']; + if (o == 'yes' || o == 'true' || o == '1') { + return 1; + } else if (o == "-1") { + return -1; + } else { + return 0; + } +} + +converter.add_ways(). + matching('highway', /^(motorway|trunk|primary|secondary)(_link)?$/). + to_layer('major_roads'). + with_attribute('type', 'highway'). + with_attribute('ref'). + with_attribute('name'). + with_attribute('oneway', convert_oneway). + with_attribute('maxspeed') + +var minor_roads = 'tertiary|unclassified|residential|living_street|pedestrian|service|track|path|footway|cycleway|road|steps'; + +converter.add_ways(). + matching('highway', minor_roads). + to_layer('minor_roads'). + with_attribute('type', 'highway'). + with_attribute('ref'). + with_attribute('name'). + with_attribute('oneway', convert_oneway). + with_attribute('maxspeed'); + +converter.add_areas(). + matching('highway', minor_roads). + matching('area', 'yes'). + to_layer('plazas'). + with_attribute('name'); + +var reader = new osmium.Reader(input_file); +var buffer = reader.read_all(); +converter.convert(buffer); + diff --git a/demo/converter/roads.js b/demo/converter/roads.js new file mode 100755 index 0000000..1ff6de0 --- /dev/null +++ b/demo/converter/roads.js @@ -0,0 +1,92 @@ +#!/usr/bin/env node + +var osmium = require('../../'); + +if (process.argv.length != 4) { + console.log("Usage: " + process.argv[0] + ' ' + process.argv[1] + " OSMFILE DBFILE"); + process.exit(1); +} + +var input_file = process.argv[2]; +var output_file = process.argv[3]; + +var converter = new osmium.Converter({ output: output_file, show_layers: true }); + +// ---- layers ---- + +converter.create_layer('turning_circles'). + with_attribute('osm_id', 'string'); + +converter.create_layer('traffic_signals'). + with_attribute('osm_id', 'string'); + +converter.create_layer('major_roads', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'). + with_attribute('ref', 'string'). + with_attribute('oneway', 'integer'). + with_attribute('maxspeed', 'integer'); + +converter.create_layer('minor_roads', 'linestring'). + with_attribute('osm_id', 'integer'). + with_attribute('type', 'string'). + with_attribute('name', 'string'). + with_attribute('ref', 'string'). + with_attribute('oneway', 'integer'). + with_attribute('maxspeed', 'integer'); + +converter.create_layer('plazas', 'multipolygon'). + with_attribute('osm_id', 'integer'). + with_attribute('name', 'string'); + + +// ---- rules ---- + +converter.add_nodes(). + matching('highway', 'traffic_signals'). + to_layer('traffic_signals'); + +converter.add_nodes(). + matching('highway', 'turning_circle'). + to_layer('turning_circles'); + +function convert_oneway(tags) { + var o = tags['oneway']; + if (o == 'yes' || o == 'true' || o == '1') { + return 1; + } else if (o == "-1") { + return -1; + } else { + return 0; + } +} + +converter.add_ways(). + matching('highway', /^(motorway|trunk|primary|secondary)(_link)?$/). + to_layer('major_roads'). + with_attribute('type', 'highway'). + with_attribute('ref'). + with_attribute('name'). + with_attribute('oneway', convert_oneway). + with_attribute('maxspeed') + +var minor_roads = 'tertiary|unclassified|residential|living_street|pedestrian|service|track|path|footway|cycleway|road|steps'; + +converter.add_ways(). + matching('highway', minor_roads). + to_layer('minor_roads'). + with_attribute('type', 'highway'). + with_attribute('ref'). + with_attribute('name'). + with_attribute('oneway', convert_oneway). + with_attribute('maxspeed'); + +converter.add_areas(). + matching('highway', minor_roads). + matching('area', 'yes'). + to_layer('plazas'). + with_attribute('name'); + +converter.convert(input_file); + diff --git a/demo/count/README.md b/demo/count/README.md new file mode 100644 index 0000000..0e8cdbf --- /dev/null +++ b/demo/count/README.md @@ -0,0 +1,8 @@ +# count + +Count the number of nodes, ways, and relations in an OSM file. + +## Usage + + ./index.js ../../test/data/winthrop.osm + diff --git a/demo/count/index.js b/demo/count/index.js new file mode 100755 index 0000000..87bcadb --- /dev/null +++ b/demo/count/index.js @@ -0,0 +1,35 @@ +#!/usr/bin/env node + +var osmium = require('../../'); + +if (process.argv.length != 3) { + console.log("Usage: " + process.argv[0] + ' ' + process.argv[1] + " OSMFILE"); + process.exit(1); +} + +var input_filename = process.argv[2]; + +// ===================================== + +var handler = new osmium.Handler(); + +var nodes=0, ways=0, relations=0; + +handler.on('node', function(node) { + nodes++; +}); + +handler.on('way', function(way) { + ways++; +}); + +handler.on('relation', function(relation) { + relations++; +}); + +var reader = new osmium.Reader(input_filename); +osmium.apply(reader, handler); +console.log("Nodes: " + nodes); +console.log("Ways: " + ways); +console.log("Relations: " + relations); + diff --git a/demo/count/package.json b/demo/count/package.json new file mode 100644 index 0000000..71993f6 --- /dev/null +++ b/demo/count/package.json @@ -0,0 +1,6 @@ +{ + "name": "test", + "version": "0.0.0", + "dependencies": { + } +} diff --git a/demo/histstat/README.md b/demo/histstat/README.md new file mode 100644 index 0000000..2e556a4 --- /dev/null +++ b/demo/histstat/README.md @@ -0,0 +1,13 @@ +# histstat + +Reads OSM history file and outputs the number of highways at the beginning of +each year. + +## Install + + npm install + +## Usage + + ./index.js OSMFILE + diff --git a/demo/histstat/index.js b/demo/histstat/index.js new file mode 100755 index 0000000..fb2c666 --- /dev/null +++ b/demo/histstat/index.js @@ -0,0 +1,46 @@ +#!/usr/bin/env node + +var osmium = require('../../'); + +if (process.argv.length != 3) { + console.log("Usage: " + process.argv[0] + ' ' + process.argv[1] + " OSMFILE"); + process.exit(1); +} + +var input_filename = process.argv[2]; + +// ===================================== + +var handler = new osmium.Handler(); + +var count = 0; +handler.on('way', function(way) { + if (way.tags('highway')) { + count++; + } +}); + +console.log("Reading input file into memory...\n"); +var reader = new osmium.Reader(input_filename); +var buffer = reader.read_all(); +reader.close(); + + +var year = 2008; +var endyear = (new Date()).getYear() + 1900; + +console.log("Calculating stats for years " + year + " to " + endyear + "\n"); + +while (year <= endyear) { + var date = new Date(year, 1, 1); + + var tbuffer = buffer.filter_point_in_time(date); + + osmium.apply(tbuffer, handler); + tbuffer.clear(); + console.log(year + ": " + count); + + count = 0; + year++; +} + diff --git a/demo/histstat/package.json b/demo/histstat/package.json new file mode 100644 index 0000000..71993f6 --- /dev/null +++ b/demo/histstat/package.json @@ -0,0 +1,6 @@ +{ + "name": "test", + "version": "0.0.0", + "dependencies": { + } +} diff --git a/demo/multipolygon/README.md b/demo/multipolygon/README.md new file mode 100644 index 0000000..d209f2c --- /dev/null +++ b/demo/multipolygon/README.md @@ -0,0 +1,12 @@ +# multipolygon + +Reads OSM file and outputs some data for landuse areas. + +## Install + + npm install + +## Usage + + ./index.js ../../test/data/winthrop.osm winthrop.csv + diff --git a/demo/multipolygon/index.js b/demo/multipolygon/index.js new file mode 100755 index 0000000..f536a75 --- /dev/null +++ b/demo/multipolygon/index.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +var osmium = require('../../'); +var buffered_writer = require('buffered-writer'); + +if (process.argv.length != 4) { + console.log("Usage: " + process.argv[0] + ' ' + process.argv[1] + " OSMFILE OUTFILE"); + process.exit(1); +} + +var input_filename = process.argv[2]; +var output_filename = process.argv[3]; + +var stream = buffered_writer.open(output_filename); + +// ===================================== + +var handler = new osmium.Handler(); + +handler.on('area', function(area) { + var landuse = area.tags('landuse'); + if (landuse) { + stream.write('a' + area.id + ' ' + landuse + ' ' + (area.tags('name') || '') + ' ' + area.wkt() + "\n"); + } +}); + +handler.on('done', function() { + stream.close(); +}); + +var mp = new osmium.MultipolygonCollector(); + +var reader = new osmium.Reader(input_filename); +mp.read_relations(reader); +reader.close(); + +reader = new osmium.Reader(input_filename); +var location_handler = new osmium.LocationHandler(); +osmium.apply(reader, location_handler, handler, mp.handler(handler)); +reader.close(); + diff --git a/demo/multipolygon/package.json b/demo/multipolygon/package.json new file mode 100644 index 0000000..2635237 --- /dev/null +++ b/demo/multipolygon/package.json @@ -0,0 +1,7 @@ +{ + "name": "test", + "version": "0.0.0", + "dependencies": { + "buffered-writer": "*" + } +} diff --git a/doc/tutorial.md b/doc/tutorial.md index 32931c9..5150a3c 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -357,6 +357,117 @@ This is, of course, only the "geometry part" of a full feature, you have to add the rest yourself. See the `demo/geojson-stream` example for a complete program using the GeoJSON function. +## Working with Multipolygons + +OSM doesn't have a data type for areas or polygons. Instead areas are stored +as closed ways (ie first node == last node) or relations tagged as +`type=multipolygon`. Osmium can hide this complexity and create pseudo-objects +called "Areass" that are either based on closed ways or on those multipoygon +relations. Usually OSM files have to be read twice to allow this, though. In +the first pass, relations are read and prepared, in the second pass nodes and +ways are read and everything is assembled. In addition to the `node`, `way`, +and `relation` callbacks, you can define an `area` callback. + +Here is an example: + + var handler = new osmium.Handler(); + + handler.on('area', function(area) { + var landuse = area.tags('landuse'); + if (landuse) { + console.log(area.wkt() + ' ' + landuse); + } + }); + + var mp = new osmium.MultipolygonCollector(); + + var reader = new osmium.Reader(input_filename); + mp.read_relations(reader); + reader.close(); + + reader = new osmium.Reader(input_filename); + var location_handler = new osmium.LocationHandler(); + osmium.apply(reader, location_handler, handler, mp.handler(handler)); + reader.close(); + +The code looks a bit complicated, because it is modelled after the C++ it is +based on. It is likely we'll make this easier at some point. You can not re-use +the reader from the first pass, you have to create a new one for the second +pass. + + +## Working With Buffers + +Instead of calling `apply()` you can call `read()` on the Reader and you'll get +an `osmium.Buffer` with zero or more OSM entities in it. If there is no more +data in the file, `read()` returns `undefined`: + + var reader = new osmium.Reader("foo.osm"); + var buffer; + while (buffer = reader.read()) { + // do something here + } + +You can call `apply()` with a `Buffer` and handlers, just like you would do +with the `Reader`: + + osmium.apply(buffer, handler1, handler2); + +There are no guarantees how many entities are in one of those buffers. They can +even be empty, but usually they will contain a few thousand entities, so they +are "small" in comparison to a big OSM data file. So if you call `apply()` on a +`Buffer` it will return much sooner than when calling `apply()` on the +`Reader`. This allows you some amount of control over how fast the input is +read. + + var reader = new osmium.Reader("foo.osm"); + var buffer; + while (buffer = reader.read()) { + osmium.apply(buffer, handler1, handler2); + // wait here if needed to slow down reading the file + } + +Note that calling `apply()` repeatedly in this way on the buffers instead of +once on the `Reader`, confuses the `done`, `init`, and `before_*` and `after_*` +handlers. You will get those handlers called for each `apply()` separately. + +### Iterating Over the Contents of a Buffer + +Instead of calling `apply()` you can iterate over the contents of the buffer by +calling `next()`: + + var object; + while (object = buffer.next()) { + console.log(object.id()); + } + +`buffer.next()` returns `undefined` when there is no more data. + +If you use the `buffer.next()` call, you'll get the next object, whatever that +is, you have to check with `object instanceof osmium.Node` or so if you got the +right type. Note that you can not use the `LocationHandler` this way. + +Together you can read the content of a file like this: + + var reader = new osmium.Reader("foo.osm"); + var buffer; + while (buffer = reader.read()) { + var object; + while (object = buffer.next()) { + // do something here with object + } + } + +### Creating an Osmium Buffer From a Node Buffer + +You can also create an `osmium.Buffer` from a `node.Buffer`: + + var node_buffer = new node.Buffer; + // fill it with OSM data somehow + var osmium_buffer = new osmium.Buffer(node_buffer); + +This buffer can now be used like the buffers we got from the `Reader`. + ## A Complete Example Finally here is a complete example to get you started: This parses an OSM file diff --git a/lib/osmium.js b/lib/osmium.js index f31365c..2f76c5a 100644 --- a/lib/osmium.js +++ b/lib/osmium.js @@ -56,3 +56,294 @@ exports.Way.prototype.geojson = function() { }; } +exports.Converter = function(args) { + if (args === undefined) { + args = {}; + } + + this.show_layers = args.show_layers ? true : false; + this.output_name = args.output || "out.db"; + + function Layer(name, geom_type) { + this.name = name; + this.geom_type = geom_type.toUpperCase(); + + if (this.geom_type != 'POINT' && this.geom_type != 'LINESTRING' && this.geom_type != 'MULTIPOLYGON') { + throw new Error('Unknown geometry type: "' + geom_type + '" (allowed are: "POINT", "LINESTRING", and "MULTIPOLYGON")'); + } + + this.attributes = []; + this.attribute_names = {}; + + this.with_attribute = function(name, type) { + var attribute_type = type.toUpperCase(); + if (attribute_type != 'INTEGER' && attribute_type != 'STRING' && attribute_type != 'BOOL' && attribute_type != 'REAL') { + throw new Error('Unknown attribute type: ' + type); + } + var attribute = { name: name, type: attribute_type }; + this.attributes.push(attribute); + this.attribute_names[name] = attribute; + return this; + } + } + + var layers = {}; + + function Filter(key, value) { + this.key = key; + + if (value == '*') { + this.value = null; + } else { + this.value = value; + } + + if (typeof(value) == 'string' && value.match(/\|/)) { + value = value.split('|'); + } + + if (value == null) { + this.match = function(obj) { + return !!obj.tags(key); + }; + } else if (typeof(value) == 'string') { + this.match = function(obj) { + return obj.tags(key) == value; + }; + } else if (value instanceof Array) { + this.match = function(obj) { + var val = obj.tags(key); + if (! val) { + return false; + } + return value.indexOf(val) != -1; + }; + } else if (value instanceof RegExp) { + this.match = function(obj) { + return obj.tags(key) && value.test(obj.tags(key)); + } + } else { + throw new Error('Can not understand rule'); + } + } + + function Rule(type) { + this.type = type; + + this.layer = null; + this.filters = []; + this.attrs = {}; + + this.matching = function(key, value) { + this.filters.push(new Filter(key, value)); + return this; + }; + + this.to_layer = function(name) { + if (! layers[name]) { + throw new Error('Unknown layer: ' + name); + } + this.layer = name; + return this; + }; + + this.with_attribute = function(attr, key) { + if (this.layer == null) { + throw new Error('Layer not set for rule ' + key + '=' + value); + } + + if (! layers[this.layer].attribute_names[attr]) { + throw new Error("There is no attribute named '" + attr + "' in layer '" + this.layer + "'"); + } + + if (key instanceof Function) { + this.attrs[attr] = key; + } else if (key == null) { + this.attrs[attr] = function(tags) { + return tags[attr]; + }; + } else { + this.attrs[attr] = function(tags) { + return tags[key]; + }; + } + + return this; + }; + + this.match = function(osm_object) { + var result = true; + this.filters.forEach(function(filter) { + if (!filter.match(osm_object)) { + result = false; + } + }); + return result; + }; + } + + this.create_layer = function(name, geom_type) { + if (geom_type == undefined) { + geom_type = 'POINT'; + } + var layer = new Layer(name, geom_type); + layers[name] = layer; + return layer; + } + + var rules = { + node: [], + way: [], + area: [] + }; + + this.rule = function(object_type) { + var rule = new Rule(object_type); + rules[object_type].push(rule); + return rule; + } + + this.add_nodes = function() { + return this.rule('node'); + } + + this.add_ways = function() { + return this.rule('way'); + } + + this.add_areas = function() { + return this.rule('area'); + } + + function tags2attributes(id, tags, attrs) { + var obj = { osm_id: id }; + for (var a in attrs) { + obj[a] = attrs[a](tags); + } + return obj; + } + + function convert(osm_object) { + rules[osm_object.type].forEach(function(rule) { + if (rule.match(osm_object)) { + try { + var attributes = tags2attributes(osm_object.id, osm_object.tags(), rule.attrs); + var p = [osm_object.wkb()]; + var layer = layers[rule.layer]; + layer.attributes.forEach(function(attribute) { + p.push(attributes[attribute.name]); + }); + layer.insert.run.apply(layer.insert, p); + } catch (e) { + // ignore broken geometries + } + } + }); + } + + var handler = new osmium.Handler; + handler.on('node', convert); + handler.on('way', convert); + handler.on('area', convert); + + this.convert = function(input) { + + var fs = require('fs'); + if (fs.existsSync(this.output_name)) { + console.log("Output database file '" + this.output_name + "' exists. Refusing to overwrite it."); + process.exit(1); + } + + // setup database + var sqlite = require('spatialite'); + var db = new sqlite.Database(this.output_name); + db.serialize(); + + db.spatialite(); + db.run("PRAGMA synchronous = OFF;"); // otherwise it is very slow + db.run("SELECT InitSpatialMetaData('WGS84');"); + + var show_layers = this.show_layers; + + // setup layers in database + for (var t in layers) { + var layer = layers[t]; + + if (show_layers) { + console.log('Layer: ' + layer.name + ' (' + layer.geom_type + ')'); + } + + db.run("CREATE TABLE " + layer.name + " (id INTEGER PRIMARY KEY);"); + db.run("SELECT AddGeometryColumn('" + layer.name + "', 'geom', 4326, '" + layer.geom_type + "', 2);"); + + var insert = "INSERT INTO " + layer.name + " (geom"; + var qm = ''; + + layer.attributes.forEach(function(attribute) { + if (show_layers) { + console.log(' ' + (attribute.name + ' ').substr(0, 11) + attribute.type); + } + db.run("ALTER TABLE " + layer.name + " ADD COLUMN " + attribute.name + " " + attribute.type + ";"); + insert += ", " + attribute.name; + qm += ", ?"; + }); + + insert += ") VALUES (GeomFromWKB(?, 4326)" + qm + ");"; + + layer.insert = db.prepare(insert); + if (show_layers) { + console.log(''); + } + } + + // convert data + console.log("Converting data..."); + if (rules.area.length > 0) { + console.log(" First pass. Reading relations..."); + var mp = new osmium.MultipolygonCollector(); + + if (input instanceof osmium.Buffer) { + mp.read_relations(input); + } else { + var reader = new osmium.Reader(input, { 'relation': true }); + mp.read_relations(reader); + reader.close(); + } + + console.log(" Second pass. Reading nodes and ways..."); + var location_handler = new osmium.LocationHandler(); + location_handler.ignoreErrors(); + if (input instanceof osmium.Buffer) { + osmium.apply(input, location_handler, handler, mp.handler(handler)); + } else { + reader = new osmium.Reader(input, { 'node': true, 'way': true }); + osmium.apply(reader, location_handler, handler, mp.handler(handler)); + reader.close(); + } + } else { + console.log(" Reading everything in one pass..."); + + var location_handler = new osmium.LocationHandler(); + location_handler.ignoreErrors(); + if (input instanceof osmium.Buffer) { + osmium.apply(input, location_handler, handler); + } else { + var reader = new osmium.Reader(input); + osmium.apply(reader, location_handler, handler); + reader.close(); + } + } + + // cleanup + console.log("Cleanup..."); + for (var layer in layers) { + layers[layer].insert.finalize(); + } + + db.close(function() { + console.log("Done."); + }); + }; + +}; + diff --git a/package.json b/package.json index 28707e4..46e21cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osmium", - "version": "0.2.0", + "version": "0.3.0", "description": "Node.js bindings to Osmium", "url": "https://github.com/osmcode/node-osmium", "homepage": "http://osmcode.org/node-osmium", diff --git a/src/apply.cpp b/src/apply.cpp index 9c5f8ff..18fa436 100644 --- a/src/apply.cpp +++ b/src/apply.cpp @@ -16,6 +16,8 @@ #include "buffer_wrap.hpp" #include "handler.hpp" #include "location_handler_wrap.hpp" +#include "multipolygon_collector_wrap.hpp" +#include "multipolygon_handler_wrap.hpp" #include "reader_wrap.hpp" #include "utils.hpp" @@ -37,6 +39,10 @@ namespace node_osmium { osmium::apply_item(m_entity, handler); } + void operator()(osmium::area::MultipolygonCollector<osmium::area::Assembler>::HandlerPass2& handler) const { + osmium::apply_item(m_entity, handler); + } + }; // struct visitor_type struct visitor_before_after_type : public boost::static_visitor<> { @@ -57,6 +63,9 @@ namespace node_osmium { void operator()(location_handler_type& visitor) const { } + void operator()(osmium::area::MultipolygonCollector<osmium::area::Assembler>::HandlerPass2& handler) const { + } + void operator()(JSHandler& visitor) const { switch (m_last) { case osmium::item_type::undefined: @@ -100,7 +109,7 @@ namespace node_osmium { }; // struct visitor_before_after - typedef boost::variant<location_handler_type&, JSHandler&> some_handler_type; + typedef boost::variant<location_handler_type&, JSHandler&, osmium::area::MultipolygonCollector<osmium::area::Assembler>::HandlerPass2&> some_handler_type; template <class TIter> v8::Handle<v8::Value> apply_iterator(TIter it, TIter end, std::vector<some_handler_type>& handlers) { @@ -165,6 +174,8 @@ namespace node_osmium { handlers.push_back(unwrap<JSHandler>(obj)); } else if (LocationHandlerWrap::constructor->HasInstance(obj)) { handlers.push_back(unwrap<LocationHandlerWrap>(obj)); + } else if (MultipolygonHandlerWrap::constructor->HasInstance(obj)) { + handlers.push_back(unwrap<MultipolygonHandlerWrap>(obj)); } } diff --git a/src/apply.hpp b/src/apply.hpp index 903327f..e0a5115 100644 --- a/src/apply.hpp +++ b/src/apply.hpp @@ -1,12 +1,8 @@ #ifndef APPLY_HPP #define APPLY_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop +// v8/node +#include "include_v8.hpp" namespace node_osmium { diff --git a/src/buffer_wrap.cpp b/src/buffer_wrap.cpp index 6f38cb2..0e03ec5 100644 --- a/src/buffer_wrap.cpp +++ b/src/buffer_wrap.cpp @@ -2,11 +2,16 @@ // node #include <node_buffer.h> +// osmium +#include <osmium/diff_iterator.hpp> + // node-osmium +#include "node_osmium.hpp" #include "buffer_wrap.hpp" #include "osm_node_wrap.hpp" #include "osm_way_wrap.hpp" #include "osm_relation_wrap.hpp" +#include "osm_area_wrap.hpp" #include "osm_changeset_wrap.hpp" #include "utils.hpp" @@ -18,9 +23,11 @@ namespace node_osmium { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(BufferWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("Buffer")); + constructor->SetClassName(symbol_Buffer); + node::SetPrototypeMethod(constructor, "clear", clear); node::SetPrototypeMethod(constructor, "next", next); - target->Set(v8::String::NewSymbol("Buffer"), constructor->GetFunction()); + node::SetPrototypeMethod(constructor, "filter_point_in_time", filter_point_in_time); + target->Set(symbol_Buffer, constructor->GetFunction()); } v8::Handle<v8::Value> BufferWrap::New(const v8::Arguments& args) { @@ -32,8 +39,8 @@ namespace node_osmium { auto obj = args[0]->ToObject(); if (node::Buffer::HasInstance(obj)) { osmium::memory::Buffer buffer(reinterpret_cast<unsigned char*>(node::Buffer::Data(obj)), node::Buffer::Length(obj)); - BufferWrap* bw = new BufferWrap(std::move(buffer)); - bw->Wrap(args.This()); + BufferWrap* buffer_wrap = new BufferWrap(std::move(buffer)); + buffer_wrap->Wrap(args.This()); return args.This(); } } @@ -43,31 +50,26 @@ namespace node_osmium { v8::Handle<v8::Value> BufferWrap::next(const v8::Arguments& args) { BufferWrap* buffer_wrap = node::ObjectWrap::Unwrap<BufferWrap>(args.This()); v8::HandleScope scope; - if (buffer_wrap->m_iterator == buffer_wrap->m_this->end()) { + if (buffer_wrap->m_iterator == buffer_wrap->m_this.end()) { return scope.Close(v8::Undefined()); } osmium::OSMEntity& entity = *buffer_wrap->m_iterator; ++buffer_wrap->m_iterator; switch (entity.type()) { case osmium::item_type::node: { - v8::Handle<v8::Value> ext = v8::External::New(new OSMNodeWrap(entity)); - v8::Local<v8::Object> obj = OSMNodeWrap::constructor->GetFunction()->NewInstance(1, &ext); - return scope.Close(obj); + return scope.Close(new_external<OSMNodeWrap>(entity)); } case osmium::item_type::way: { - v8::Handle<v8::Value> ext = v8::External::New(new OSMWayWrap(entity)); - v8::Local<v8::Object> obj = OSMWayWrap::constructor->GetFunction()->NewInstance(1, &ext); - return scope.Close(obj); + return scope.Close(new_external<OSMWayWrap>(entity)); } case osmium::item_type::relation: { - v8::Handle<v8::Value> ext = v8::External::New(new OSMRelationWrap(entity)); - v8::Local<v8::Object> obj = OSMRelationWrap::constructor->GetFunction()->NewInstance(1, &ext); - return scope.Close(obj); + return scope.Close(new_external<OSMRelationWrap>(entity)); + } + case osmium::item_type::area: { + return scope.Close(new_external<OSMAreaWrap>(entity)); } case osmium::item_type::changeset: { - v8::Handle<v8::Value> ext = v8::External::New(new OSMChangesetWrap(entity)); - v8::Local<v8::Object> obj = OSMChangesetWrap::constructor->GetFunction()->NewInstance(1, &ext); - return scope.Close(obj); + return scope.Close(new_external<OSMChangesetWrap>(entity)); } default: break; @@ -75,5 +77,40 @@ namespace node_osmium { return scope.Close(v8::Undefined()); } + v8::Handle<v8::Value> BufferWrap::filter_point_in_time(const v8::Arguments& args) { + v8::HandleScope scope; + if (args.Length() != 1) { + return ThrowException(v8::Exception::TypeError(v8::String::New("please provide a point in time as first and only argument"))); + } + + osmium::Timestamp point_in_time; + if (args[0]->IsInt32()) { + point_in_time = args[0]->Int32Value(); + } else if (args[0]->IsString()) { + point_in_time = osmium::Timestamp(*v8::String::Utf8Value(args[0]->ToString())); + } else if (args[0]->IsDate()) { + point_in_time = osmium::Timestamp(static_cast<int32_t>(v8::Date::Cast(*args[0])->NumberValue() / 1000)); + } + + typedef osmium::DiffIterator<osmium::memory::Buffer::t_iterator<osmium::OSMObject>> diff_iterator; + osmium::memory::Buffer& buffer = unwrap<BufferWrap>(args.This()); + osmium::memory::Buffer fbuffer(buffer.committed(), osmium::memory::Buffer::auto_grow::yes); + { + auto dbegin = diff_iterator(buffer.begin<osmium::OSMObject>(), buffer.end<osmium::OSMObject>()); + auto dend = diff_iterator(buffer.end<osmium::OSMObject>(), buffer.end<osmium::OSMObject>()); + + std::for_each(dbegin, dend, [point_in_time, &fbuffer](const osmium::DiffObject& d) { + if (((d.end_time() == 0 || d.end_time() > point_in_time) && + d.start_time() <= point_in_time) && + d.curr().visible()) { + fbuffer.add_item(d.curr()); + fbuffer.commit(); + } + }); + } + + return scope.Close(new_external<BufferWrap>(std::move(fbuffer))); + } + } // namespace node_osmium diff --git a/src/buffer_wrap.hpp b/src/buffer_wrap.hpp index c2db592..c218fe4 100644 --- a/src/buffer_wrap.hpp +++ b/src/buffer_wrap.hpp @@ -4,16 +4,8 @@ // c++ #include <memory> -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop - -// node -#include <node.h> -#include <node_version.h> +// v8/node +#include "include_v8.hpp" #include <node_object_wrap.h> // osmium @@ -23,10 +15,16 @@ namespace node_osmium { class BufferWrap : public node::ObjectWrap { - std::shared_ptr<osmium::memory::Buffer> m_this; + osmium::memory::Buffer m_this; osmium::memory::Buffer::iterator m_iterator; + static v8::Handle<v8::Value> clear(const v8::Arguments& args) { + BufferWrap* buffer_wrap = node::ObjectWrap::Unwrap<BufferWrap>(args.This()); + buffer_wrap->m_this = std::move(osmium::memory::Buffer()); + } + static v8::Handle<v8::Value> next(const v8::Arguments& args); + static v8::Handle<v8::Value> filter_point_in_time(const v8::Arguments& args); public: @@ -35,18 +33,17 @@ namespace node_osmium { static v8::Handle<v8::Value> New(const v8::Arguments& args); BufferWrap(osmium::memory::Buffer&& buffer) : ObjectWrap(), - m_this(std::make_shared<osmium::memory::Buffer>(std::move(buffer))), - m_iterator(m_this->begin()) { + m_this(std::move(buffer)), + m_iterator(m_this.begin()) { } osmium::memory::Buffer& get() { - return *m_this; + return m_this; } private: - ~BufferWrap() { - } + ~BufferWrap() = default; }; // class BufferWrap diff --git a/src/file_wrap.cpp b/src/file_wrap.cpp index 0bacd01..78e6dea 100644 --- a/src/file_wrap.cpp +++ b/src/file_wrap.cpp @@ -2,12 +2,11 @@ // c++ #include <exception> -// v8 -#include <v8.h> - // node #include <node_buffer.h> +// node-osmium +#include "node_osmium.hpp" #include "file_wrap.hpp" namespace node_osmium { @@ -18,8 +17,8 @@ namespace node_osmium { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(FileWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("File")); - target->Set(v8::String::NewSymbol("File"), constructor->GetFunction()); + constructor->SetClassName(symbol_File); + target->Set(symbol_File, constructor->GetFunction()); } v8::Handle<v8::Value> FileWrap::New(const v8::Arguments& args) { diff --git a/src/file_wrap.hpp b/src/file_wrap.hpp index 2020d5e..195c3f5 100644 --- a/src/file_wrap.hpp +++ b/src/file_wrap.hpp @@ -5,14 +5,8 @@ #include <memory> #include <string> -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop - -// node +// v8/node +#include "include_v8.hpp" #include <node_object_wrap.h> // osmium @@ -22,7 +16,7 @@ namespace node_osmium { class FileWrap : public node::ObjectWrap { - std::shared_ptr<osmium::io::File> m_this; + osmium::io::File m_this; public: @@ -32,17 +26,16 @@ namespace node_osmium { FileWrap(osmium::io::File&& file) : node::ObjectWrap(), - m_this(std::make_shared<osmium::io::File>(file)) { + m_this(std::move(file)) { } osmium::io::File& get() { - return *m_this; + return m_this; } private: - ~FileWrap() { - } + ~FileWrap() = default; }; // class FileWrap diff --git a/src/handler.cpp b/src/handler.cpp index 5482fd1..bbce412 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -2,9 +2,6 @@ // c++ #include <string> -// v8 -#include <v8.h> - // node #include <node.h> #include <node_object_wrap.h> @@ -13,10 +10,12 @@ #include <osmium/osm/object.hpp> // node-osmium +#include "node_osmium.hpp" #include "handler.hpp" #include "osm_node_wrap.hpp" #include "osm_way_wrap.hpp" #include "osm_relation_wrap.hpp" +#include "osm_area_wrap.hpp" #include "osm_changeset_wrap.hpp" #include "utils.hpp" @@ -29,10 +28,10 @@ namespace node_osmium { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(JSHandler::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("Handler")); + constructor->SetClassName(symbol_Handler); node::SetPrototypeMethod(constructor, "on", on); node::SetPrototypeMethod(constructor, "options", options); - target->Set(v8::String::NewSymbol("Handler"), constructor->GetFunction()); + target->Set(symbol_Handler, constructor->GetFunction()); symbol_tagged_nodes_only = NODE_PSYMBOL("tagged_nodes_only"); } @@ -57,6 +56,8 @@ namespace node_osmium { relation_cb.Dispose(); after_relations_cb.Dispose(); + area_cb.Dispose(); + before_changesets_cb.Dispose(); changeset_cb.Dispose(); after_changesets_cb.Dispose(); @@ -76,8 +77,8 @@ namespace node_osmium { b->Wrap(args.This()); return args.This(); } else { - JSHandler* h = new JSHandler(); - h->Wrap(args.This()); + JSHandler* jshandler = new JSHandler(); + jshandler->Wrap(args.This()); return args.This(); } return scope.Close(v8::Undefined()); @@ -118,6 +119,9 @@ namespace node_osmium { } else if (callback_name == "relation") { handler.relation_cb.Dispose(); handler.relation_cb = v8::Persistent<v8::Function>::New(callback); + } else if (callback_name == "area") { + handler.area_cb.Dispose(); + handler.area_cb = v8::Persistent<v8::Function>::New(callback); } else if (callback_name == "changeset") { handler.changeset_cb.Dispose(); handler.changeset_cb = v8::Persistent<v8::Function>::New(callback); @@ -165,9 +169,7 @@ namespace node_osmium { } v8::HandleScope scope; - v8::Handle<v8::Value> ext = v8::External::New(new TWrapped(entity)); - v8::Local<v8::Object> obj = TWrapped::constructor->GetFunction()->NewInstance(1, &ext); - v8::Local<v8::Value> argv[1] = { obj }; + v8::Local<v8::Value> argv[1] = { new_external<TWrapped>(entity) }; function->Call(v8::Context::GetCurrent()->Global(), 1, argv); } @@ -198,6 +200,11 @@ namespace node_osmium { call_callback_with_entity<OSMRelationWrap>(relation_cb, entity); } break; + case osmium::item_type::area: + if (!area_cb.IsEmpty()) { + call_callback_with_entity<OSMAreaWrap>(area_cb, entity); + } + break; case osmium::item_type::changeset: if (!changeset_cb.IsEmpty()) { call_callback_with_entity<OSMChangesetWrap>(changeset_cb, entity); diff --git a/src/handler.hpp b/src/handler.hpp index 843874e..922ef5c 100644 --- a/src/handler.hpp +++ b/src/handler.hpp @@ -1,14 +1,8 @@ #ifndef HANDLER_HPP #define HANDLER_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop - -// node +// v8/node +#include "include_v8.hpp" #include <node_object_wrap.h> // osmium @@ -38,6 +32,8 @@ namespace node_osmium { v8::Persistent<v8::Function> relation_cb; v8::Persistent<v8::Function> after_relations_cb; + v8::Persistent<v8::Function> area_cb; + v8::Persistent<v8::Function> before_changesets_cb; v8::Persistent<v8::Function> changeset_cb; v8::Persistent<v8::Function> after_changesets_cb; diff --git a/src/apply.hpp b/src/include_v8.hpp similarity index 50% copy from src/apply.hpp copy to src/include_v8.hpp index 903327f..6b72ffd 100644 --- a/src/apply.hpp +++ b/src/include_v8.hpp @@ -1,17 +1,10 @@ -#ifndef APPLY_HPP -#define APPLY_HPP +#ifndef INCLUDE_V8_HPP +#define INCLUDE_V8_HPP -// v8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wctor-dtor-privacy" #pragma GCC diagnostic ignored "-Wunused-parameter" #include <v8.h> #pragma GCC diagnostic pop -namespace node_osmium { - - v8::Handle<v8::Value> apply(const v8::Arguments& args); - -} // namespace node_osmium - -#endif // APPLY_HPP +#endif // INCLUDE_V8_HPP diff --git a/src/location_handler_wrap.cpp b/src/location_handler_wrap.cpp index 63a2e10..b7b9e8b 100644 --- a/src/location_handler_wrap.cpp +++ b/src/location_handler_wrap.cpp @@ -1,4 +1,6 @@ +// node-osmium +#include "node_osmium.hpp" #include "location_handler_wrap.hpp" #include "utils.hpp" @@ -10,10 +12,10 @@ namespace node_osmium { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(LocationHandlerWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("LocationHandler")); + constructor->SetClassName(symbol_LocationHandler); node::SetPrototypeMethod(constructor, "clear", clear); node::SetPrototypeMethod(constructor, "ignoreErrors", ignoreErrors); - target->Set(v8::String::NewSymbol("LocationHandler"), constructor->GetFunction()); + target->Set(symbol_LocationHandler, constructor->GetFunction()); } v8::Handle<v8::Value> LocationHandlerWrap::New(const v8::Arguments& args) { diff --git a/src/location_handler_wrap.hpp b/src/location_handler_wrap.hpp index 1d47a6e..70e85b2 100644 --- a/src/location_handler_wrap.hpp +++ b/src/location_handler_wrap.hpp @@ -3,15 +3,10 @@ // c++ #include <memory> +#include <string> -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop - -// node +// v8/node +#include "include_v8.hpp" #include <node_object_wrap.h> // osmium @@ -67,7 +62,7 @@ namespace node_osmium { std::unique_ptr<index_pos_type> m_index_pos; std::unique_ptr<index_neg_type> m_index_neg; - std::shared_ptr<location_handler_type> m_this; + std::unique_ptr<location_handler_type> m_this; static v8::Handle<v8::Value> clear(const v8::Arguments& args); static v8::Handle<v8::Value> ignoreErrors(const v8::Arguments& args); @@ -82,7 +77,7 @@ namespace node_osmium { ObjectWrap(), m_index_pos(node_cache_factory(cache_type)), m_index_neg(new index_neg_type), - m_this(std::make_shared<location_handler_type>(*m_index_pos, *m_index_neg)) { + m_this(new location_handler_type(*m_index_pos, *m_index_neg)) { if (!m_index_pos) { throw std::runtime_error("unknown node cache type"); } @@ -94,8 +89,7 @@ namespace node_osmium { private: - ~LocationHandlerWrap() { - } + ~LocationHandlerWrap() = default; }; // class LocationHandlerWrap diff --git a/src/multipolygon_collector_wrap.cpp b/src/multipolygon_collector_wrap.cpp new file mode 100644 index 0000000..cedad87 --- /dev/null +++ b/src/multipolygon_collector_wrap.cpp @@ -0,0 +1,97 @@ + +// node +#include <node_buffer.h> + +// node-osmium +#include "node_osmium.hpp" +#include "multipolygon_collector_wrap.hpp" +#include "multipolygon_handler_wrap.hpp" +#include "handler.hpp" +#include "buffer_wrap.hpp" +#include "reader_wrap.hpp" +#include "utils.hpp" +#include "apply.hpp" + +namespace node_osmium { + + v8::Persistent<v8::FunctionTemplate> MultipolygonCollectorWrap::constructor; + + void MultipolygonCollectorWrap::Initialize(v8::Handle<v8::Object> target) { + v8::HandleScope scope; + constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(MultipolygonCollectorWrap::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(symbol_MultipolygonCollector); + node::SetPrototypeMethod(constructor, "read_relations", read_relations); + node::SetPrototypeMethod(constructor, "handler", handler); + target->Set(symbol_MultipolygonCollector, constructor->GetFunction()); + } + + v8::Handle<v8::Value> MultipolygonCollectorWrap::New(const v8::Arguments& args) { + v8::HandleScope scope; + + if (!args.IsConstructCall()) { + return ThrowException(v8::Exception::Error(v8::String::New("Cannot call constructor as function, you need to use 'new' keyword"))); + } + + if (args.Length() != 0) { + return ThrowException(v8::Exception::TypeError(v8::String::New("MultipolygonCollector is constructed without arguments"))); + } + + try { + MultipolygonCollectorWrap* multipolygon_collector_wrap = new MultipolygonCollectorWrap(); + multipolygon_collector_wrap->Wrap(args.This()); + return args.This(); + } catch (const std::exception& e) { + return ThrowException(v8::Exception::TypeError(v8::String::New(e.what()))); + } + + return scope.Close(v8::Undefined()); + } + + v8::Handle<v8::Value> MultipolygonCollectorWrap::read_relations(const v8::Arguments& args) { + v8::HandleScope scope; + if (args.Length() != 1 || !args[0]->IsObject()) { + return ThrowException(v8::Exception::Error(v8::String::New("call MultipolygonCollector.read_relation() with Reader or Buffer object"))); + } + try { + if (ReaderWrap::constructor->HasInstance(args[0]->ToObject())) { + osmium::io::Reader& reader = unwrap<ReaderWrap>(args[0]->ToObject()); + unwrap<MultipolygonCollectorWrap>(args.This()).read_relations(reader); + } else if (BufferWrap::constructor->HasInstance(args[0]->ToObject())) { + osmium::memory::Buffer& buffer = unwrap<BufferWrap>(args[0]->ToObject()); + unwrap<MultipolygonCollectorWrap>(args.This()).read_relations(buffer.begin(), buffer.end()); + } else { + return ThrowException(v8::Exception::Error(v8::String::New("call MultipolygonCollector.read_relation() with Reader or Buffer object"))); + } + } catch (const std::exception& e) { + std::string msg("osmium error: "); + msg += e.what(); + return ThrowException(v8::Exception::Error(v8::String::New(msg.c_str()))); + } + return scope.Close(v8::Undefined()); + } + + v8::Handle<v8::Value> MultipolygonCollectorWrap::handler(const v8::Arguments& args) { + v8::HandleScope scope; + if (args.Length() != 1 || !args[0]->IsObject() || !JSHandler::constructor->HasInstance(args[0]->ToObject())) { + return ThrowException(v8::Exception::Error(v8::String::New("call MultipolygonCollector.handler() with Handler object"))); + } + try { + JSHandler& handler = unwrap<JSHandler>(args[0]->ToObject()); + auto& mc_handler = unwrap<MultipolygonCollectorWrap>(args.This()).handler([&handler](const osmium::memory::Buffer& area_buffer) { + for (const osmium::OSMEntity& entity : area_buffer) { + handler.dispatch_entity(entity); + } + }); + return scope.Close(new_external<MultipolygonHandlerWrap>(mc_handler)); + + } catch (const std::exception& e) { + std::string msg("osmium error: "); + msg += e.what(); + return ThrowException(v8::Exception::Error(v8::String::New(msg.c_str()))); + } + return scope.Close(v8::Undefined()); + } + +} // namespace node_osmium + diff --git a/src/multipolygon_collector_wrap.hpp b/src/multipolygon_collector_wrap.hpp new file mode 100644 index 0000000..b59c5fb --- /dev/null +++ b/src/multipolygon_collector_wrap.hpp @@ -0,0 +1,46 @@ +#ifndef MULTIPOLYGON_COLLECTOR_WRAP_HPP +#define MULTIPOLYGON_COLLECTOR_WRAP_HPP + +// v8/node +#include "include_v8.hpp" +#include <node_object_wrap.h> + +// osmium +#include <osmium/area/multipolygon_collector.hpp> +#include <osmium/area/assembler.hpp> + +namespace node_osmium { + + class MultipolygonCollectorWrap : public node::ObjectWrap { + + static v8::Handle<v8::Value> read_relations(const v8::Arguments& args); + static v8::Handle<v8::Value> handler(const v8::Arguments& args); + + osmium::area::Assembler::config_type m_assembler_config; + osmium::area::MultipolygonCollector<osmium::area::Assembler> m_collector; + + public: + + static v8::Persistent<v8::FunctionTemplate> constructor; + static void Initialize(v8::Handle<v8::Object> target); + static v8::Handle<v8::Value> New(const v8::Arguments& args); + + MultipolygonCollectorWrap() : + node::ObjectWrap(), + m_assembler_config(), + m_collector(m_assembler_config) { + } + + osmium::area::MultipolygonCollector<osmium::area::Assembler>& get() { + return m_collector; + } + + private: + + ~MultipolygonCollectorWrap() = default; + + }; // class MultipolygonCollectorWrap + +} // namespace node_osmium + +#endif // MULTIPOLYGON_COLLECTOR_WRAP_HPP diff --git a/src/multipolygon_handler_wrap.cpp b/src/multipolygon_handler_wrap.cpp new file mode 100644 index 0000000..e715bfe --- /dev/null +++ b/src/multipolygon_handler_wrap.cpp @@ -0,0 +1,33 @@ + +// node +#include <node_buffer.h> + +// node-osmium +#include "node_osmium.hpp" +#include "multipolygon_handler_wrap.hpp" +#include "utils.hpp" + +namespace node_osmium { + + v8::Persistent<v8::FunctionTemplate> MultipolygonHandlerWrap::constructor; + + void MultipolygonHandlerWrap::Initialize(v8::Handle<v8::Object> target) { + v8::HandleScope scope; + constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(MultipolygonHandlerWrap::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(symbol_MultipolygonHandler); + target->Set(symbol_MultipolygonHandler, constructor->GetFunction()); + } + + v8::Handle<v8::Value> MultipolygonHandlerWrap::New(const v8::Arguments& args) { + if (args.Length() == 1 && args[0]->IsExternal()) { + v8::Local<v8::External> ext = v8::Local<v8::External>::Cast(args[0]); + static_cast<MultipolygonHandlerWrap*>(ext->Value())->Wrap(args.This()); + return args.This(); + } else { + return ThrowException(v8::Exception::TypeError(v8::String::New("osmium.MultipolygonHandler cannot be created in Javascript"))); + } + } + +} // namespace node_osmium + diff --git a/src/multipolygon_handler_wrap.hpp b/src/multipolygon_handler_wrap.hpp new file mode 100644 index 0000000..155cae1 --- /dev/null +++ b/src/multipolygon_handler_wrap.hpp @@ -0,0 +1,42 @@ +#ifndef MULTIPOLYGON_HANDLER_WRAP_HPP +#define MULTIPOLYGON_HANDLER_WRAP_HPP + +// v8/node +#include "include_v8.hpp" +#include <node_object_wrap.h> + +// osmium +#include <osmium/area/multipolygon_collector.hpp> +#include <osmium/area/assembler.hpp> + +namespace node_osmium { + + class MultipolygonHandlerWrap : public node::ObjectWrap { + + typedef osmium::area::MultipolygonCollector<osmium::area::Assembler>::HandlerPass2 handler_type; + handler_type m_handler; + + public: + + static v8::Persistent<v8::FunctionTemplate> constructor; + static void Initialize(v8::Handle<v8::Object> target); + static v8::Handle<v8::Value> New(const v8::Arguments& args); + + MultipolygonHandlerWrap(handler_type& handler) : + node::ObjectWrap(), + m_handler(handler) { + } + + handler_type& get() { + return m_handler; + } + + private: + + ~MultipolygonHandlerWrap() = default; + + }; // class MultipolygonHandlerWrap + +} // namespace node_osmium + +#endif // MULTIPOLYGON_HANDLER_WRAP_HPP diff --git a/src/node_osmium.cpp b/src/node_osmium.cpp index 16b6e47..fc439d8 100644 --- a/src/node_osmium.cpp +++ b/src/node_osmium.cpp @@ -1,9 +1,3 @@ -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop // node #include <node.h> @@ -21,6 +15,9 @@ #include "file_wrap.hpp" #include "handler.hpp" #include "location_handler_wrap.hpp" +#include "multipolygon_collector_wrap.hpp" +#include "multipolygon_handler_wrap.hpp" +#include "osm_area_wrap.hpp" #include "osm_changeset_wrap.hpp" #include "osm_node_wrap.hpp" #include "osm_relation_wrap.hpp" @@ -33,6 +30,41 @@ namespace node_osmium { osmium::geom::WKBFactory<> wkb_factory; osmium::geom::WKTFactory<> wkt_factory; + v8::Persistent<v8::String> symbol_OSMEntity; + v8::Persistent<v8::String> symbol_OSMObject; + + v8::Persistent<v8::String> symbol_Node; + v8::Persistent<v8::String> symbol_node; + + v8::Persistent<v8::String> symbol_Way; + v8::Persistent<v8::String> symbol_way; + + v8::Persistent<v8::String> symbol_Relation; + v8::Persistent<v8::String> symbol_relation; + v8::Persistent<v8::String> symbol_type; + v8::Persistent<v8::String> symbol_ref; + v8::Persistent<v8::String> symbol_role; + + v8::Persistent<v8::String> symbol_Area; + v8::Persistent<v8::String> symbol_area; + + v8::Persistent<v8::String> symbol_Changeset; + v8::Persistent<v8::String> symbol_changeset; + + v8::Persistent<v8::String> symbol_Coordinates; + v8::Persistent<v8::String> symbol_Box; + + v8::Persistent<v8::String> symbol_generator; + v8::Persistent<v8::String> symbol_bounds; + + v8::Persistent<v8::String> symbol_Buffer; + v8::Persistent<v8::String> symbol_File; + v8::Persistent<v8::String> symbol_Handler; + v8::Persistent<v8::String> symbol_LocationHandler; + v8::Persistent<v8::String> symbol_MultipolygonCollector; + v8::Persistent<v8::String> symbol_MultipolygonHandler; + v8::Persistent<v8::String> symbol_Reader; + extern "C" { static void start(v8::Handle<v8::Object> target) { v8::HandleScope scope; @@ -40,12 +72,43 @@ namespace node_osmium { node::SetMethod(target, "apply", node_osmium::apply); + symbol_OSMEntity = NODE_PSYMBOL("OSMEntity"); + symbol_OSMObject = NODE_PSYMBOL("OSMObject"); + symbol_Node = NODE_PSYMBOL("Node"); + symbol_node = NODE_PSYMBOL("node"); + symbol_Way = NODE_PSYMBOL("Way"); + symbol_way = NODE_PSYMBOL("way"); + symbol_Relation = NODE_PSYMBOL("Relation"); + symbol_relation = NODE_PSYMBOL("relation"); + symbol_type = NODE_PSYMBOL("type"); + symbol_ref = NODE_PSYMBOL("ref"); + symbol_role = NODE_PSYMBOL("role"); + symbol_Area = NODE_PSYMBOL("Area"); + symbol_area = NODE_PSYMBOL("area"); + symbol_Changeset = NODE_PSYMBOL("Changeset"); + symbol_changeset = NODE_PSYMBOL("changeset"); + symbol_Coordinates = NODE_PSYMBOL("Coordinates"); + symbol_Box = NODE_PSYMBOL("Box"); + symbol_generator = NODE_PSYMBOL("generator"); + symbol_bounds = NODE_PSYMBOL("bounds"); + + symbol_Buffer = NODE_PSYMBOL("Buffer"); + symbol_File = NODE_PSYMBOL("File"); + symbol_Handler = NODE_PSYMBOL("Handler"); + symbol_LocationHandler = NODE_PSYMBOL("LocationHandler"); + symbol_MultipolygonCollector = NODE_PSYMBOL("MultipolygonCollector"); + symbol_MultipolygonHandler = NODE_PSYMBOL("MultipolygonHandler"); + symbol_Reader = NODE_PSYMBOL("Reader"); + node_osmium::OSMEntityWrap::Initialize(target); node_osmium::OSMObjectWrap::Initialize(target); node_osmium::OSMNodeWrap::Initialize(target); node_osmium::OSMWayWrap::Initialize(target); node_osmium::OSMRelationWrap::Initialize(target); + node_osmium::OSMAreaWrap::Initialize(target); node_osmium::OSMChangesetWrap::Initialize(target); + node_osmium::MultipolygonCollectorWrap::Initialize(target); + node_osmium::MultipolygonHandlerWrap::Initialize(target); node_osmium::LocationHandlerWrap::Initialize(target); node_osmium::JSHandler::Initialize(target); node_osmium::FileWrap::Initialize(target); diff --git a/src/node_osmium.hpp b/src/node_osmium.hpp new file mode 100644 index 0000000..8ab7915 --- /dev/null +++ b/src/node_osmium.hpp @@ -0,0 +1,45 @@ +#ifndef NODE_OSMIUM +#define NODE_OSMIUM + +#include "include_v8.hpp" + +namespace node_osmium { + + extern v8::Persistent<v8::String> symbol_OSMEntity; + extern v8::Persistent<v8::String> symbol_OSMObject; + + extern v8::Persistent<v8::String> symbol_Node; + extern v8::Persistent<v8::String> symbol_node; + + extern v8::Persistent<v8::String> symbol_Way; + extern v8::Persistent<v8::String> symbol_way; + + extern v8::Persistent<v8::String> symbol_Relation; + extern v8::Persistent<v8::String> symbol_relation; + extern v8::Persistent<v8::String> symbol_type; + extern v8::Persistent<v8::String> symbol_ref; + extern v8::Persistent<v8::String> symbol_role; + + extern v8::Persistent<v8::String> symbol_Area; + extern v8::Persistent<v8::String> symbol_area; + + extern v8::Persistent<v8::String> symbol_Changeset; + extern v8::Persistent<v8::String> symbol_changeset; + + extern v8::Persistent<v8::String> symbol_Coordinates; + extern v8::Persistent<v8::String> symbol_Box; + + extern v8::Persistent<v8::String> symbol_generator; + extern v8::Persistent<v8::String> symbol_bounds; + + extern v8::Persistent<v8::String> symbol_Buffer; + extern v8::Persistent<v8::String> symbol_File; + extern v8::Persistent<v8::String> symbol_Handler; + extern v8::Persistent<v8::String> symbol_LocationHandler; + extern v8::Persistent<v8::String> symbol_MultipolygonCollector; + extern v8::Persistent<v8::String> symbol_MultipolygonHandler; + extern v8::Persistent<v8::String> symbol_Reader; + +} // namespace node_osmium + +#endif // NODE_OSMIUM diff --git a/src/osm_area_wrap.cpp b/src/osm_area_wrap.cpp new file mode 100644 index 0000000..5bf59db --- /dev/null +++ b/src/osm_area_wrap.cpp @@ -0,0 +1,71 @@ + +// node +#include <node_buffer.h> +#include <node_version.h> + +// osmium +#include <osmium/geom/wkb.hpp> +#include <osmium/geom/wkt.hpp> + +// node-osmium +#include "osm_area_wrap.hpp" + +namespace node_osmium { + + extern osmium::geom::WKBFactory<> wkb_factory; + extern osmium::geom::WKTFactory<> wkt_factory; + extern v8::Persistent<v8::Object> module; + + v8::Persistent<v8::FunctionTemplate> OSMAreaWrap::constructor; + + void OSMAreaWrap::Initialize(v8::Handle<v8::Object> target) { + v8::HandleScope scope; + constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(OSMAreaWrap::New)); + constructor->Inherit(OSMObjectWrap::constructor); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(symbol_Area); + auto attributes = static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); + set_accessor(constructor, "type", get_type, attributes); + node::SetPrototypeMethod(constructor, "wkb", wkb); + node::SetPrototypeMethod(constructor, "wkt", wkt); + target->Set(symbol_Area, constructor->GetFunction()); + } + + v8::Handle<v8::Value> OSMAreaWrap::New(const v8::Arguments& args) { + if (args.Length() == 1 && args[0]->IsExternal()) { + v8::Local<v8::External> ext = v8::Local<v8::External>::Cast(args[0]); + static_cast<OSMAreaWrap*>(ext->Value())->Wrap(args.This()); + return args.This(); + } else { + return ThrowException(v8::Exception::TypeError(v8::String::New("osmium.Area cannot be created in Javascript"))); + } + } + + v8::Handle<v8::Value> OSMAreaWrap::wkb(const v8::Arguments& args) { + v8::HandleScope scope; + + try { + std::string wkb { wkb_factory.create_multipolygon(wrapped(args.This())) }; +#if NODE_VERSION_AT_LEAST(0, 10, 0) + return scope.Close(node::Buffer::New(wkb.data(), wkb.size())->handle_); +#else + return scope.Close(node::Buffer::New(const_cast<char*>(wkb.data()), wkb.size())->handle_); +#endif + } catch (std::runtime_error& e) { + return ThrowException(v8::Exception::Error(v8::String::New(e.what()))); + } + } + + v8::Handle<v8::Value> OSMAreaWrap::wkt(const v8::Arguments& args) { + v8::HandleScope scope; + + try { + std::string wkt { wkt_factory.create_multipolygon(wrapped(args.This())) }; + return scope.Close(v8::String::New(wkt.c_str())); + } catch (std::runtime_error& e) { + return ThrowException(v8::Exception::Error(v8::String::New(e.what()))); + } + } + +} // namespace node_osmium + diff --git a/src/osm_area_wrap.hpp b/src/osm_area_wrap.hpp new file mode 100644 index 0000000..f62aaf7 --- /dev/null +++ b/src/osm_area_wrap.hpp @@ -0,0 +1,52 @@ +#ifndef OSM_AREA_WRAP_HPP +#define OSM_AREA_WRAP_HPP + +// v8/node +#include "include_v8.hpp" + +// osmium +#include <osmium/osm/area.hpp> +namespace osmium { + class OSMEntity; +} + +// node-osmium +#include "node_osmium.hpp" +#include "osm_entity_wrap.hpp" +#include "osm_object_wrap.hpp" +#include "utils.hpp" + +namespace node_osmium { + + class OSMAreaWrap : public OSMObjectWrap { + + static v8::Handle<v8::Value> get_type(v8::Local<v8::String> property, const v8::AccessorInfo& info) { + return symbol_area; + } + + static v8::Handle<v8::Value> wkb(const v8::Arguments& args); + static v8::Handle<v8::Value> wkt(const v8::Arguments& args); + + public: + + static v8::Persistent<v8::FunctionTemplate> constructor; + static void Initialize(v8::Handle<v8::Object> target); + static v8::Handle<v8::Value> New(const v8::Arguments& args); + + static const osmium::Area& wrapped(const v8::Local<v8::Object>& object) { + return static_cast<const osmium::Area&>(unwrap<OSMEntityWrap>(object)); + } + + OSMAreaWrap(const osmium::OSMEntity& entity) : + OSMObjectWrap(entity) { + } + + private: + + ~OSMAreaWrap() = default; + + }; // class OSMAreaWrap + +} // namespace node_osmium + +#endif // OSM_AREA_WRAP_HPP diff --git a/src/osm_changeset_wrap.cpp b/src/osm_changeset_wrap.cpp index f8a02ca..e2c78f5 100644 --- a/src/osm_changeset_wrap.cpp +++ b/src/osm_changeset_wrap.cpp @@ -1,4 +1,5 @@ +// node-osmium #include "osm_changeset_wrap.hpp" #include "utils.hpp" @@ -10,11 +11,13 @@ namespace node_osmium { void OSMChangesetWrap::Initialize(v8::Handle<v8::Object> target) { v8::HandleScope scope; + constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(OSMChangesetWrap::New)); constructor->Inherit(OSMEntityWrap::constructor); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("Changeset")); + constructor->SetClassName(symbol_Changeset); auto attributes = static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); + set_accessor(constructor, "type", get_type, attributes); set_accessor(constructor, "id", get_id, attributes); set_accessor(constructor, "uid", get_uid, attributes); set_accessor(constructor, "user", get_user, attributes); @@ -25,7 +28,7 @@ namespace node_osmium { set_accessor(constructor, "closed", get_closed, attributes); set_accessor(constructor, "bounds", get_bounds, attributes); node::SetPrototypeMethod(constructor, "tags", tags); - target->Set(v8::String::NewSymbol("Changeset"), constructor->GetFunction()); + target->Set(symbol_Changeset, constructor->GetFunction()); } v8::Handle<v8::Value> OSMChangesetWrap::New(const v8::Arguments& args) { @@ -49,7 +52,7 @@ namespace node_osmium { v8::Handle<v8::Value> OSMChangesetWrap::get_uid(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).uid())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).uid())); } v8::Handle<v8::Value> OSMChangesetWrap::get_user(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { @@ -59,17 +62,17 @@ namespace node_osmium { v8::Handle<v8::Value> OSMChangesetWrap::get_num_changes(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).num_changes())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).num_changes())); } v8::Handle<v8::Value> OSMChangesetWrap::get_created_at(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).created_at())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).created_at())); } v8::Handle<v8::Value> OSMChangesetWrap::get_closed_at(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).closed_at())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).closed_at())); } v8::Handle<v8::Value> OSMChangesetWrap::get_open(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { diff --git a/src/osm_changeset_wrap.hpp b/src/osm_changeset_wrap.hpp index ca605f9..b490045 100644 --- a/src/osm_changeset_wrap.hpp +++ b/src/osm_changeset_wrap.hpp @@ -1,12 +1,8 @@ #ifndef OSM_CHANGESET_WRAP_HPP #define OSM_CHANGESET_WRAP_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop +// v8/node +#include "include_v8.hpp" // osmium #include <osmium/osm/changeset.hpp> @@ -15,6 +11,7 @@ namespace osmium { } // node-osmium +#include "node_osmium.hpp" #include "osm_entity_wrap.hpp" #include "utils.hpp" @@ -22,6 +19,10 @@ namespace node_osmium { class OSMChangesetWrap : public OSMEntityWrap { + static v8::Handle<v8::Value> get_type(v8::Local<v8::String> property, const v8::AccessorInfo& info) { + return symbol_changeset; + } + static v8::Handle<v8::Value> get_id(v8::Local<v8::String> property, const v8::AccessorInfo& info); static v8::Handle<v8::Value> get_uid(v8::Local<v8::String> property, const v8::AccessorInfo& info); static v8::Handle<v8::Value> get_user(v8::Local<v8::String> property, const v8::AccessorInfo& info); @@ -47,6 +48,10 @@ namespace node_osmium { OSMEntityWrap(entity) { } + private: + + ~OSMChangesetWrap() = default; + }; // class OSMChangesetWrap } // namespace node_osmium diff --git a/src/osm_entity_wrap.cpp b/src/osm_entity_wrap.cpp index 91191f0..51122bd 100644 --- a/src/osm_entity_wrap.cpp +++ b/src/osm_entity_wrap.cpp @@ -1,4 +1,6 @@ +// node-osmium +#include "node_osmium.hpp" #include "osm_entity_wrap.hpp" namespace node_osmium { @@ -9,8 +11,8 @@ namespace node_osmium { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(OSMEntityWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("OSMEntity")); - target->Set(v8::String::NewSymbol("OSMEntity"), constructor->GetFunction()); + constructor->SetClassName(symbol_OSMEntity); + target->Set(symbol_OSMEntity, constructor->GetFunction()); } v8::Handle<v8::Value> OSMEntityWrap::New(const v8::Arguments& args) { diff --git a/src/osm_entity_wrap.hpp b/src/osm_entity_wrap.hpp index bf25136..0e14587 100644 --- a/src/osm_entity_wrap.hpp +++ b/src/osm_entity_wrap.hpp @@ -1,14 +1,8 @@ #ifndef OSM_ENTITY_WRAP_HPP #define OSM_ENTITY_WRAP_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop - -// node +// v8/node +#include "include_v8.hpp" #include <node_object_wrap.h> // osmium @@ -71,6 +65,10 @@ namespace node_osmium { return *m_entity; } + protected: + + virtual ~OSMEntityWrap() = default; + }; // class OSMEntityWrap } // namespace node_osmium diff --git a/src/osm_node_wrap.cpp b/src/osm_node_wrap.cpp index 57a0f2c..3d21eb5 100644 --- a/src/osm_node_wrap.cpp +++ b/src/osm_node_wrap.cpp @@ -23,15 +23,16 @@ namespace node_osmium { constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(OSMNodeWrap::New)); constructor->Inherit(OSMObjectWrap::constructor); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("Node")); + constructor->SetClassName(symbol_Node); node::SetPrototypeMethod(constructor, "wkb", wkb); node::SetPrototypeMethod(constructor, "wkt", wkt); auto attributes = static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); + set_accessor(constructor, "type", get_type, attributes); set_accessor(constructor, "location", get_coordinates, attributes); set_accessor(constructor, "coordinates", get_coordinates, attributes); set_accessor(constructor, "lon", get_lon, attributes); set_accessor(constructor, "lat", get_lat, attributes); - target->Set(v8::String::NewSymbol("Node"), constructor->GetFunction()); + target->Set(symbol_Node, constructor->GetFunction()); } v8::Handle<v8::Value> OSMNodeWrap::New(const v8::Arguments& args) { @@ -47,24 +48,36 @@ namespace node_osmium { v8::Handle<v8::Value> OSMNodeWrap::get_coordinates(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - auto lon = v8::Number::New(wrapped(info.This()).location().lon()); - auto lat = v8::Number::New(wrapped(info.This()).location().lat()); - - auto cf = module->Get(v8::String::NewSymbol("Coordinates")); + auto cf = module->Get(symbol_Coordinates); assert(cf->IsFunction()); + const osmium::Location& location = wrapped(info.This()).location(); + if (!location) { + return scope.Close(v8::Local<v8::Function>::Cast(cf)->NewInstance()); + } + + v8::Local<v8::Value> lon = v8::Number::New(location.lon_without_check()); + v8::Local<v8::Value> lat = v8::Number::New(location.lat_without_check()); v8::Local<v8::Value> argv[2] = { lon, lat }; return scope.Close(v8::Local<v8::Function>::Cast(cf)->NewInstance(2, argv)); } v8::Handle<v8::Value> OSMNodeWrap::get_lon(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).location().lon())); + try { + return scope.Close(v8::Number::New(wrapped(info.This()).location().lon())); + } catch (osmium::invalid_location&) { + return scope.Close(v8::Undefined()); + } } v8::Handle<v8::Value> OSMNodeWrap::get_lat(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).location().lat())); + try { + return scope.Close(v8::Number::New(wrapped(info.This()).location().lat())); + } catch (osmium::invalid_location&) { + return scope.Close(v8::Undefined()); + } } v8::Handle<v8::Value> OSMNodeWrap::wkb(const v8::Arguments& args) { diff --git a/src/osm_node_wrap.hpp b/src/osm_node_wrap.hpp index 157df91..5ae12da 100644 --- a/src/osm_node_wrap.hpp +++ b/src/osm_node_wrap.hpp @@ -1,12 +1,8 @@ #ifndef OSM_NODE_WRAP_HPP #define OSM_NODE_WRAP_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop +// v8/node +#include "include_v8.hpp" // osmium #include <osmium/osm/node.hpp> @@ -15,6 +11,7 @@ namespace osmium { } // node-osmium +#include "node_osmium.hpp" #include "osm_entity_wrap.hpp" #include "osm_object_wrap.hpp" #include "utils.hpp" @@ -23,6 +20,10 @@ namespace node_osmium { class OSMNodeWrap : public OSMObjectWrap { + static v8::Handle<v8::Value> get_type(v8::Local<v8::String> property, const v8::AccessorInfo& info) { + return symbol_node; + } + static v8::Handle<v8::Value> get_coordinates(v8::Local<v8::String> property, const v8::AccessorInfo& info); static v8::Handle<v8::Value> get_lon(v8::Local<v8::String> property, const v8::AccessorInfo& info); static v8::Handle<v8::Value> get_lat(v8::Local<v8::String> property, const v8::AccessorInfo& info); @@ -45,8 +46,7 @@ namespace node_osmium { private: - ~OSMNodeWrap() { - } + ~OSMNodeWrap() = default; }; // class OSMNodeWrap diff --git a/src/osm_object_wrap.cpp b/src/osm_object_wrap.cpp index 710018a..b771947 100644 --- a/src/osm_object_wrap.cpp +++ b/src/osm_object_wrap.cpp @@ -1,4 +1,6 @@ +// node-osmium +#include "node_osmium.hpp" #include "osm_object_wrap.hpp" namespace node_osmium { @@ -9,7 +11,7 @@ namespace node_osmium { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(OSMObjectWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("OSMObject")); + constructor->SetClassName(symbol_OSMObject); auto attributes = static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); set_accessor(constructor, "id", get_id, attributes); set_accessor(constructor, "version", get_version, attributes); @@ -19,7 +21,7 @@ namespace node_osmium { set_accessor(constructor, "uid", get_uid, attributes); set_accessor(constructor, "user", get_user, attributes); node::SetPrototypeMethod(constructor, "tags", tags); - target->Set(v8::String::NewSymbol("OSMObject"), constructor->GetFunction()); + target->Set(symbol_OSMObject, constructor->GetFunction()); } v8::Handle<v8::Value> OSMObjectWrap::New(const v8::Arguments& args) { @@ -43,12 +45,12 @@ namespace node_osmium { v8::Handle<v8::Value> OSMObjectWrap::get_version(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).version())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).version())); } v8::Handle<v8::Value> OSMObjectWrap::get_changeset(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).changeset())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).changeset())); } v8::Handle<v8::Value> OSMObjectWrap::get_visible(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { @@ -58,12 +60,12 @@ namespace node_osmium { v8::Handle<v8::Value> OSMObjectWrap::get_timestamp(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).timestamp())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).timestamp())); } v8::Handle<v8::Value> OSMObjectWrap::get_uid(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).uid())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).uid())); } v8::Handle<v8::Value> OSMObjectWrap::get_user(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { diff --git a/src/osm_object_wrap.hpp b/src/osm_object_wrap.hpp index a735d93..2bf27f3 100644 --- a/src/osm_object_wrap.hpp +++ b/src/osm_object_wrap.hpp @@ -1,12 +1,8 @@ #ifndef OSM_OBJECT_WRAP_HPP #define OSM_OBJECT_WRAP_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop +// v8/node +#include "include_v8.hpp" // osmium #include <osmium/osm/object.hpp> @@ -45,6 +41,10 @@ namespace node_osmium { OSMEntityWrap(entity) { } + protected: + + virtual ~OSMObjectWrap() = default; + }; // class OSMObjectWrap } // namespace node_osmium diff --git a/src/osm_relation_wrap.cpp b/src/osm_relation_wrap.cpp index fc8b225..db30e22 100644 --- a/src/osm_relation_wrap.cpp +++ b/src/osm_relation_wrap.cpp @@ -1,29 +1,25 @@ +// node #include <node.h> -#include <osm_relation_wrap.hpp> +// node-osmium +#include "osm_relation_wrap.hpp" namespace node_osmium { v8::Persistent<v8::FunctionTemplate> OSMRelationWrap::constructor; - v8::Persistent<v8::String> OSMRelationWrap::symbol_type; - v8::Persistent<v8::String> OSMRelationWrap::symbol_ref; - v8::Persistent<v8::String> OSMRelationWrap::symbol_role; void OSMRelationWrap::Initialize(v8::Handle<v8::Object> target) { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(OSMRelationWrap::New)); constructor->Inherit(OSMObjectWrap::constructor); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("Relation")); + constructor->SetClassName(symbol_Relation); auto attributes = static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); + set_accessor(constructor, "type", get_type, attributes); set_accessor(constructor, "members_count", get_members_count, attributes); node::SetPrototypeMethod(constructor, "members", members); - target->Set(v8::String::NewSymbol("Relation"), constructor->GetFunction()); - - symbol_type = NODE_PSYMBOL("type"); - symbol_ref = NODE_PSYMBOL("ref"); - symbol_role = NODE_PSYMBOL("role"); + target->Set(symbol_Relation, constructor->GetFunction()); } v8::Handle<v8::Value> OSMRelationWrap::New(const v8::Arguments& args) { @@ -38,7 +34,7 @@ namespace node_osmium { v8::Handle<v8::Value> OSMRelationWrap::get_members_count(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).members().size())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).members().size())); } v8::Handle<v8::Value> OSMRelationWrap::members(const v8::Arguments& args) { @@ -63,11 +59,11 @@ namespace node_osmium { return scope.Close(members); } case 1: { - if (!args[0]->IsNumber()) { + if (!args[0]->IsUint32()) { return ThrowException(v8::Exception::TypeError(v8::String::New("call members() without parameters or the index of the member you want"))); } - int n = static_cast<int>(args[0]->ToNumber()->Value()); - if (n >= 0 && n < static_cast<int>(relation.members().size())) { + uint32_t n = args[0]->ToUint32()->Value(); + if (n < relation.members().size()) { auto it = relation.members().begin(); std::advance(it, n); const osmium::RelationMember& member = *it; diff --git a/src/osm_relation_wrap.hpp b/src/osm_relation_wrap.hpp index 534fe48..cc88ce9 100644 --- a/src/osm_relation_wrap.hpp +++ b/src/osm_relation_wrap.hpp @@ -1,12 +1,8 @@ #ifndef OSM_RELATION_WRAP_HPP #define OSM_RELATION_WRAP_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop +// v8/node +#include "include_v8.hpp" // osmium #include <osmium/osm/relation.hpp> @@ -15,6 +11,7 @@ namespace osmium { } // node-osmium +#include "node_osmium.hpp" #include "osm_entity_wrap.hpp" #include "osm_object_wrap.hpp" #include "utils.hpp" @@ -23,9 +20,9 @@ namespace node_osmium { class OSMRelationWrap : public OSMObjectWrap { - static v8::Persistent<v8::String> symbol_type; - static v8::Persistent<v8::String> symbol_ref; - static v8::Persistent<v8::String> symbol_role; + static v8::Handle<v8::Value> get_type(v8::Local<v8::String> property, const v8::AccessorInfo& info) { + return symbol_relation; + } static v8::Handle<v8::Value> get_members_count(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info); static v8::Handle<v8::Value> members(const v8::Arguments& args); @@ -46,8 +43,7 @@ namespace node_osmium { private: - ~OSMRelationWrap() { - } + ~OSMRelationWrap() = default; }; // class OSMRelationWrap diff --git a/src/osm_way_wrap.cpp b/src/osm_way_wrap.cpp index 86991e3..b26c92e 100644 --- a/src/osm_way_wrap.cpp +++ b/src/osm_way_wrap.cpp @@ -23,14 +23,15 @@ namespace node_osmium { constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(OSMWayWrap::New)); constructor->Inherit(OSMObjectWrap::constructor); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("Way")); + constructor->SetClassName(symbol_Way); auto attributes = static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); + set_accessor(constructor, "type", get_type, attributes); set_accessor(constructor, "nodes_count", get_nodes_count, attributes); node::SetPrototypeMethod(constructor, "node_refs", node_refs); node::SetPrototypeMethod(constructor, "node_coordinates", node_coordinates); node::SetPrototypeMethod(constructor, "wkb", wkb); node::SetPrototypeMethod(constructor, "wkt", wkt); - target->Set(v8::String::NewSymbol("Way"), constructor->GetFunction()); + target->Set(symbol_Way, constructor->GetFunction()); } v8::Handle<v8::Value> OSMWayWrap::New(const v8::Arguments& args) { @@ -71,7 +72,7 @@ namespace node_osmium { v8::Handle<v8::Value> OSMWayWrap::get_nodes_count(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) { v8::HandleScope scope; - return scope.Close(v8::Number::New(wrapped(info.This()).nodes().size())); + return scope.Close(v8::Uint32::New(wrapped(info.This()).nodes().size())); } v8::Handle<v8::Value> OSMWayWrap::node_refs(const v8::Arguments& args) { @@ -90,11 +91,11 @@ namespace node_osmium { return scope.Close(nodes); } case 1: { - if (!args[0]->IsNumber()) { + if (!args[0]->IsUint32()) { return ThrowException(v8::Exception::TypeError(v8::String::New("call node_refs() without parameters or the index of the node you want"))); } - int n = static_cast<int>(args[0]->ToNumber()->Value()); - if (n >= 0 && n < static_cast<int>(way.nodes().size())) { + uint32_t n = args[0]->ToUint32()->Value(); + if (n < way.nodes().size()) { return scope.Close(v8::Number::New(way.nodes()[n].ref())); } else { return ThrowException(v8::Exception::RangeError(v8::String::New("argument to node_refs() out of range"))); @@ -108,7 +109,7 @@ namespace node_osmium { v8::Handle<v8::Value> OSMWayWrap::node_coordinates(const v8::Arguments& args) { v8::HandleScope scope; - auto cf = module->Get(v8::String::NewSymbol("Coordinates")); + auto cf = module->Get(symbol_Coordinates); assert(cf->IsFunction()); const osmium::Way& way = wrapped(args.This()); @@ -130,11 +131,11 @@ namespace node_osmium { } } case 1: { - if (!args[0]->IsNumber()) { + if (!args[0]->IsUint32()) { return ThrowException(v8::Exception::TypeError(v8::String::New("call node_coordinates() without parameters or the index of the node you want"))); } - int n = static_cast<int>(args[0]->ToNumber()->Value()); - if (n >= 0 && n < static_cast<int>(way.nodes().size())) { + uint32_t n = args[0]->ToUint32()->Value(); + if (n < way.nodes().size()) { const osmium::Location location = way.nodes()[n].location(); if (location.valid()) { v8::Local<v8::Value> argv[2] = { v8::Number::New(location.lon()), v8::Number::New(location.lat()) }; diff --git a/src/osm_way_wrap.hpp b/src/osm_way_wrap.hpp index 229c4bb..1cf2724 100644 --- a/src/osm_way_wrap.hpp +++ b/src/osm_way_wrap.hpp @@ -1,12 +1,8 @@ #ifndef OSM_WAY_WRAP_HPP #define OSM_WAY_WRAP_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop +// v8/node +#include "include_v8.hpp" // osmium #include <osmium/osm/way.hpp> @@ -15,6 +11,7 @@ namespace osmium { } // node-osmium +#include "node_osmium.hpp" #include "osm_entity_wrap.hpp" #include "osm_object_wrap.hpp" #include "utils.hpp" @@ -23,6 +20,10 @@ namespace node_osmium { class OSMWayWrap : public OSMObjectWrap { + static v8::Handle<v8::Value> get_type(v8::Local<v8::String> property, const v8::AccessorInfo& info) { + return symbol_way; + } + static v8::Handle<v8::Value> get_nodes_count(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info); static v8::Handle<v8::Value> node_refs(const v8::Arguments& args); static v8::Handle<v8::Value> node_coordinates(const v8::Arguments& args); @@ -45,8 +46,7 @@ namespace node_osmium { private: - ~OSMWayWrap() { - } + ~OSMWayWrap() = default; }; // class OSMWayWrap diff --git a/src/reader_wrap.cpp b/src/reader_wrap.cpp index cdf507e..a1e2986 100644 --- a/src/reader_wrap.cpp +++ b/src/reader_wrap.cpp @@ -8,6 +8,7 @@ #include <node.h> // node-osmium +#include "node_osmium.hpp" #include "buffer_wrap.hpp" #include "file_wrap.hpp" #include "handler.hpp" @@ -26,11 +27,12 @@ namespace node_osmium { v8::HandleScope scope; constructor = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(ReaderWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(v8::String::NewSymbol("Reader")); + constructor->SetClassName(symbol_Reader); node::SetPrototypeMethod(constructor, "header", header); node::SetPrototypeMethod(constructor, "close", close); node::SetPrototypeMethod(constructor, "read", read); - target->Set(v8::String::NewSymbol("Reader"), constructor->GetFunction()); + node::SetPrototypeMethod(constructor, "read_all", read_all); + target->Set(symbol_Reader, constructor->GetFunction()); } v8::Handle<v8::Value> ReaderWrap::New(const v8::Arguments& args) { @@ -50,22 +52,22 @@ namespace node_osmium { read_which_entities = osmium::osm_entity_bits::nothing; v8::Local<v8::Object> options = args[1]->ToObject(); - v8::Local<v8::Value> want_nodes = options->Get(v8::String::NewSymbol("node")); + v8::Local<v8::Value> want_nodes = options->Get(symbol_node); if (want_nodes->IsBoolean() && want_nodes->BooleanValue()) { read_which_entities |= osmium::osm_entity_bits::node; } - v8::Local<v8::Value> want_ways = options->Get(v8::String::NewSymbol("way")); + v8::Local<v8::Value> want_ways = options->Get(symbol_way); if (want_ways->IsBoolean() && want_ways->BooleanValue()) { read_which_entities |= osmium::osm_entity_bits::way; } - v8::Local<v8::Value> want_relations = options->Get(v8::String::NewSymbol("relation")); + v8::Local<v8::Value> want_relations = options->Get(symbol_relation); if (want_relations->IsBoolean() && want_relations->BooleanValue()) { read_which_entities |= osmium::osm_entity_bits::relation; } - v8::Local<v8::Value> want_changesets = options->Get(v8::String::NewSymbol("changeset")); + v8::Local<v8::Value> want_changesets = options->Get(symbol_changeset); if (want_changesets->IsBoolean() && want_changesets->BooleanValue()) { read_which_entities |= osmium::osm_entity_bits::changeset; } @@ -73,13 +75,13 @@ namespace node_osmium { } if (args[0]->IsString()) { osmium::io::File file(*v8::String::Utf8Value(args[0])); - ReaderWrap* q = new ReaderWrap(file, read_which_entities); - q->Wrap(args.This()); + ReaderWrap* reader_wrap = new ReaderWrap(file, read_which_entities); + reader_wrap->Wrap(args.This()); return args.This(); } else if (args[0]->IsObject() && FileWrap::constructor->HasInstance(args[0]->ToObject())) { v8::Local<v8::Object> file_obj = args[0]->ToObject(); - ReaderWrap* q = new ReaderWrap(unwrap<FileWrap>(file_obj), read_which_entities); - q->Wrap(args.This()); + ReaderWrap* reader_wrap = new ReaderWrap(unwrap<FileWrap>(file_obj), read_which_entities); + reader_wrap->Wrap(args.This()); return args.This(); } else { return ThrowException(v8::Exception::TypeError(v8::String::New("please provide a File object or string for the first argument when creating a Reader"))); @@ -94,7 +96,7 @@ namespace node_osmium { v8::HandleScope scope; v8::Local<v8::Object> obj = v8::Object::New(); const osmium::io::Header& header = unwrap<ReaderWrap>(args.This()).header(); - obj->Set(v8::String::NewSymbol("generator"), v8::String::New(header.get("generator").c_str())); + obj->Set(symbol_generator, v8::String::New(header.get("generator").c_str())); auto bounds_array = v8::Array::New(header.boxes().size()); @@ -103,7 +105,7 @@ namespace node_osmium { bounds_array->Set(i++, create_js_box(box)); } - obj->Set(v8::String::NewSymbol("bounds"), bounds_array); + obj->Set(symbol_bounds, bounds_array); return scope.Close(obj); } @@ -124,9 +126,27 @@ namespace node_osmium { try { osmium::memory::Buffer buffer = unwrap<ReaderWrap>(args.This()).read(); if (buffer) { - v8::Handle<v8::Value> ext = v8::External::New(new BufferWrap(std::move(buffer))); - v8::Local<v8::Object> obj = BufferWrap::constructor->GetFunction()->NewInstance(1, &ext); - return scope.Close(obj); + return scope.Close(new_external<BufferWrap>(std::move(buffer))); + } + } catch (const std::exception& e) { + std::string msg("osmium error: "); + msg += e.what(); + return ThrowException(v8::Exception::Error(v8::String::New(msg.c_str()))); + } + return scope.Close(v8::Undefined()); + } + + v8::Handle<v8::Value> ReaderWrap::read_all(const v8::Arguments& args) { + osmium::memory::Buffer buffer(1024*1024, osmium::memory::Buffer::auto_grow::yes); + v8::HandleScope scope; + try { + osmium::io::Reader& reader = unwrap<ReaderWrap>(args.This()); + while (osmium::memory::Buffer read_buffer = reader.read()) { + buffer.add_buffer(read_buffer); + buffer.commit(); + } + if (buffer) { + return scope.Close(new_external<BufferWrap>(std::move(buffer))); } } catch (const std::exception& e) { std::string msg("osmium error: "); diff --git a/src/reader_wrap.hpp b/src/reader_wrap.hpp index 084c7ef..1d313cd 100644 --- a/src/reader_wrap.hpp +++ b/src/reader_wrap.hpp @@ -1,19 +1,8 @@ #ifndef READER_WRAP_HPP #define READER_WRAP_HPP -// c++ -#include <memory> - -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop - -// node -#include <node.h> -#include <node_version.h> +// v8/node +#include "include_v8.hpp" #include <node_object_wrap.h> // osmium @@ -30,8 +19,9 @@ namespace node_osmium { static v8::Handle<v8::Value> header(const v8::Arguments& args); static v8::Handle<v8::Value> close(const v8::Arguments& args); static v8::Handle<v8::Value> read(const v8::Arguments& args); + static v8::Handle<v8::Value> read_all(const v8::Arguments& args); - std::shared_ptr<osmium::io::Reader> m_this; + osmium::io::Reader m_this; public: @@ -41,17 +31,16 @@ namespace node_osmium { ReaderWrap(const osmium::io::File& file, osmium::osm_entity_bits::type entities) : ObjectWrap(), - m_this(std::make_shared<osmium::io::Reader>(file, entities)) { + m_this(file, entities) { } osmium::io::Reader& get() { - return *m_this; + return m_this; } private: - ~ReaderWrap() { - } + ~ReaderWrap() = default; }; // class ReaderWrap diff --git a/src/utils.cpp b/src/utils.cpp index df40fdb..b4cde2e 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -2,6 +2,7 @@ // osmium #include <osmium/osm/box.hpp> +#include "node_osmium.hpp" #include "utils.hpp" namespace node_osmium { @@ -15,9 +16,9 @@ namespace node_osmium { return scope.Close(v8::Undefined()); } - auto cf = module->Get(v8::String::NewSymbol("Coordinates")); + auto cf = module->Get(symbol_Coordinates); assert(cf->IsFunction()); - auto bf = module->Get(v8::String::NewSymbol("Box")); + auto bf = module->Get(symbol_Box); assert(bf->IsFunction()); v8::Local<v8::Value> argv_bl[2] = { v8::Number::New(box.bottom_left().lon()), v8::Number::New(box.bottom_left().lat()) }; diff --git a/src/utils.hpp b/src/utils.hpp index 331be88..a2bc4b1 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -1,14 +1,11 @@ #ifndef UTILS_HPP #define UTILS_HPP -// v8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include <v8.h> -#pragma GCC diagnostic pop - -// node +// c++ +#include <utility> + +// v8/node +#include "include_v8.hpp" #include <node_object_wrap.h> // osmium @@ -23,6 +20,13 @@ namespace node_osmium { return node::ObjectWrap::Unwrap<T>(object)->get(); } + template<class T, class... Args> + v8::Local<v8::Object> new_external(Args&&... args) { + v8::HandleScope scope; + v8::Handle<v8::Value> ext = v8::External::New(new T(std::forward<Args>(args)...)); + return scope.Close(T::constructor->GetFunction()->NewInstance(1, &ext)); + } + v8::Handle<v8::Value> create_js_box(const osmium::Box& box); } // namespace node_osmium diff --git a/test/changesets.test.js b/test/changesets.test.js index da4b366..31fd00b 100644 --- a/test/changesets.test.js +++ b/test/changesets.test.js @@ -8,6 +8,7 @@ describe('changesets', function() { var count = 0; handler.on('changeset', function(changeset) { if (count++ == 0) { + assert.equal(changeset.type, "changeset"); assert.equal(changeset.id, 15449957); assert.equal(changeset.user, "Elbert"); assert.equal(changeset.uid, 1237205); diff --git a/test/data/coordinates-problems.osm b/test/data/coordinates-problems.osm new file mode 100644 index 0000000..cd61132 --- /dev/null +++ b/test/data/coordinates-problems.osm @@ -0,0 +1,6 @@ +<?xml version='1.0' encoding='UTF-8'?> +<osm version="0.6" generator="testdata" upload="false"> + <node id="1" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.02" lat="2.03"/> <!-- lon/lat okay --> + <node id="2" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1"/> <!-- lon/lat missing --> + <node id="3" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="190" lat="190"/> <!-- outside valid range --> +</osm> diff --git a/test/osm_object_creation.test.js b/test/osm-object-creation.test.js similarity index 100% rename from test/osm_object_creation.test.js rename to test/osm-object-creation.test.js diff --git a/test/osm-objects.test.js b/test/osm-objects.test.js index 7b10669..491be4d 100644 --- a/test/osm-objects.test.js +++ b/test/osm-objects.test.js @@ -8,6 +8,7 @@ describe('basic', function() { var count = 0; handler.on('node', function(node) { if (count++ == 0) { + assert.equal(node.type, "node"); assert.equal(node.id, 50031066); assert.equal(node.visible, true); assert.equal(node.version, 2); @@ -36,6 +37,7 @@ describe('basic', function() { var count = 0; handler.on('way', function(way) { if (count++ == 0) { + assert.equal(way.type, "way"); assert.equal(way.id, 6091729); assert.equal(way.visible, true); assert.equal(way.version, 1); @@ -57,6 +59,7 @@ describe('basic', function() { var count = 0; handler.on('relation', function(relation) { if (count++ == 0) { + assert.equal(relation.type, "relation"); assert.equal(relation.id, 237891); assert.equal(relation.visible, true); assert.equal(relation.version, 2); @@ -174,4 +177,28 @@ describe('basic', function() { osmium.apply(reader, handler); }); + it('should be able to handle missing and invalid coordinates', function() { + var handler = new osmium.Handler(); + var count = 0; + handler.on('node', function(node) { + count++; + if (count == 1) { + assert.equal(node.coordinates.lon, 1.02); + assert.equal(node.coordinates.lat, 2.03); + assert.equal(node.coordinates.valid(), true); + } else if (count == 2) { + assert.equal(node.coordinates.lon, undefined); + assert.equal(node.coordinates.lat, undefined); + assert.equal(node.coordinates.valid(), false); + } else if (count == 3) { + assert.equal(node.coordinates.lon, 190); + assert.equal(node.coordinates.lat, 190); + assert.equal(node.coordinates.valid(), false); + } + }); + var file = new osmium.File(__dirname + "/data/coordinates-problems.osm"); + var reader = new osmium.Reader(file, {node: true}); + osmium.apply(reader, handler); + }); + }); diff --git a/test/reader.test.js b/test/reader.test.js index b71a8a3..fb4cb60 100644 --- a/test/reader.test.js +++ b/test/reader.test.js @@ -65,5 +65,23 @@ describe('reader', function() { osmium.apply(reader, handler); }); + it('should read a whole file with Reader.read_all()', function(done) { + var file = new osmium.File(__dirname + "/data/winthrop.osm"); + var reader = new osmium.Reader(file); + var buffer = reader.read_all(); + + var handler = new osmium.Handler(); + + var count = 0; + handler.on('node', function(node) { + if (count++ == 0) { + assert.equal(node.id, 50031066); + done(); + } + }); + + osmium.apply(buffer, handler); + }); + }); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/node-osmium.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel