This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository node-osmium.
commit 80ef48b13d5f2b35469efc5a28b3dd7c42e25b32 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Fri Mar 6 15:16:29 2015 +0100 Imported Upstream version 0.1.1 --- .travis.yml | 12 +- Makefile | 8 +- README.md | 98 +++++++------ binding.gyp | 9 +- configure | 3 - demo/geojson-stream/index.js | 9 +- package.json | 15 +- src/buffer.hpp | 9 +- src/{file.hpp => file_wrap.cpp} | 63 ++------- src/file_wrap.hpp | 59 ++++++++ src/handler.cpp | 170 ++++++++++++++++++++++ src/handler.hpp | 274 ++---------------------------------- src/node_osmium.cpp | 25 +++- src/osm_node_wrap.cpp | 78 ++++++++++ src/osm_node_wrap.hpp | 55 ++++++++ src/osm_object_wrap.cpp | 28 ++++ src/osm_object_wrap.hpp | 42 ++++++ src/osm_relation_wrap.cpp | 88 ++++++++++++ src/osm_relation_wrap.hpp | 56 ++++++++ src/osm_way_wrap.cpp | 108 ++++++++++++++ src/osm_way_wrap.hpp | 55 ++++++++ src/{reader.hpp => reader_wrap.cpp} | 140 +++++++----------- src/reader_wrap.hpp | 68 +++++++++ test/osmium.test.js | 27 +++- 24 files changed, 1017 insertions(+), 482 deletions(-) diff --git a/.travis.yml b/.travis.yml index 999579c..0f23dda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,14 @@ language: node_js node_js: - "0.10" - - "0.8" before_install: + # first test install of binary + - npm install --verbose + - make test + +install: + # next test source compile, so get dependencies - sudo apt-add-repository --yes ppa:mapnik/boost - sudo apt-add-repository --yes ppa:ubuntu-toolchain-r/test - sudo apt-get -y update -qq @@ -14,12 +19,9 @@ before_install: - make && sudo make install - cd ../../ -install: - - npm install mocha - before_script: - git clone https://github.com/osmcode/libosmium.git ../libosmium - - CXX=g++-4.7 npm install --verbose + - CXX=g++-4.7 npm install script: - make test diff --git a/Makefile b/Makefile index 32df7b4..bca59f3 100755 --- a/Makefile +++ b/Makefile @@ -1,15 +1,17 @@ all: osmium.node -osmium.node: +./build: + `npm explore npm -g -- pwd`/bin/node-gyp-bin/node-gyp configure + +osmium.node: binding.gyp Makefile ./build `npm explore npm -g -- pwd`/bin/node-gyp-bin/node-gyp --verbose build clean: - @rm -rf ./build + rm -rf ./build rm -f lib/osmium.node rebuild: @make clean - @./configure @make test/data/berlin-latest.osm.pbf: diff --git a/README.md b/README.md index 042ad4c..a69b503 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,67 @@ # node-osmium -Node.js bindings to [libosmium](https://github.com/osmcode/libosmium). +Fast and flexible Javascript library for working with OpenStreetMap data. + +Provides a bindings to the [libosmium](https://github.com/osmcode/libosmium) C++ library. [![Build Status](https://secure.travis-ci.org/osmcode/node-osmium.png)](http://travis-ci.org/osmcode/node-osmium) # Depends - - Compiler that supports `-std=c++11` (>= clang++ 3.2 || >= g++ 4.8) - Node.js v0.10.x + +# Installing + +By default, binaries are provided and no external depedencies and no compile is needed. + +Just do: + + npm install osmium + +We currently provide binaries for 64 bit OS X and 64 bit Linux. Running `npm install` on other +platforms will fall back to a source compile (see `Developing` below for build details). + +# Usage + +## Get the bounds of an `.osm` file + +```js +var osmium = require('osmium'); +var file = new osmium.File("test/data/winthrop.osm"); +var reader = new osmium.Reader(file); +console.log(reader.header()) +{ generator: 'CGImap 0.2.0', + bounds: [ -120.2024, 48.4636, -120.1569, 48.4869 ] } +``` + +## Parse a `.pbf` file and create a node handler callback to count total nodes + +```js +var osmium = require('osmium'); +var file = new osmium.File("test/data/winthrop.osm"); +var reader = new osmium.Reader(file); +var handler = new osmium.Handler(); +var nodes = 0; +handler.on('node',function(node) { + ++nodes; +}); +reader.apply(handler); +console.log(nodes); +1525 +``` + +# Developing + +If you wish to develop on `node-osmium` you can check out the code and then build like: + + git clone https://github.com/osmcode/node-osmium.git + cd node-osmium + make + make test + +## Source build dependencies + + - Compiler that supports `-std=c++11` (>= clang++ 3.2 || >= g++ 4.8) - Boost >= 1.49 with development headers - OSM-Binary - Protocol buffers @@ -42,43 +96,3 @@ Set depedencies up on OS X like: ./scripts/build_osm-pbf.sh # NOTE: in the same terminal then run the build commands # Or from a different terminal re-run `source MacOSX.sh` - -# Building - -To build the bindings: - - git clone https://github.com/osmcode/libosmium.git - git clone https://github.com/osmcode/node-osmium.git - cd node-osmium - npm install - -# Testing - -Run the tests like: - - npm install mocha - make test - -# Troubleshooting - -If you hit a test error like the below it means you need to run `make test` instead of just `npm test` so that the test data is downloaded: - - 1) osmium should be able to create an osmium.Reader: - TypeError: Open failed - -If you hit an error like the below it means you need a more recent compiler that implements the C++11 language standard - - cc1plus: error: unrecognized command line option ‘-std=c++11’ - -This error indicates you need the boost development headers installed: - - ../../include/osmium/osm/location.hpp:40:31: fatal error: boost/operators.hpp: No such file or directory - -An error like this indicates that your compiler is too old and does not support all needed c++11 features - - ../../include/osmium/io/header.hpp:55:51: sorry, unimplemented: non-static data member initializers - ../../include/osmium/io/header.hpp:55:51: error: ISO C++ forbids in-class initialization of non-const static member ‘m_has_multiple_object_versions’ - -And error like this indicates that you need to do `export CXXFLAGS=-fPIC` and then recompile `libosmpbf`: - - /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libosmpbf.a(fileformat.pb.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC diff --git a/binding.gyp b/binding.gyp index 3adfc7a..e262a27 100644 --- a/binding.gyp +++ b/binding.gyp @@ -8,7 +8,14 @@ { "target_name": "<(module_name)", "sources": [ - "src/node_osmium.cpp" + "src/node_osmium.cpp", + "src/handler.cpp", + "src/file_wrap.cpp", + "src/reader_wrap.cpp", + "src/osm_object_wrap.cpp", + "src/osm_node_wrap.cpp", + "src/osm_way_wrap.cpp", + "src/osm_relation_wrap.cpp" ], "include_dirs": [ "../libosmium/include/", diff --git a/configure b/configure deleted file mode 100755 index d0184d1..0000000 --- a/configure +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -`npm explore npm -g -- pwd`/bin/node-gyp-bin/node-gyp configure $@ \ No newline at end of file diff --git a/demo/geojson-stream/index.js b/demo/geojson-stream/index.js index fac9e63..b1da769 100755 --- a/demo/geojson-stream/index.js +++ b/demo/geojson-stream/index.js @@ -15,8 +15,13 @@ var argv = require('minimist')(process.argv, { string: 'output', }); -if (!argv.output || typeof(argv.output) != 'string') throw new Error('--output argument required (path to a new file or the keyword "stdout")'); -if (!argv.input || typeof(argv.input) != 'string') throw new Error('--input argument required (path to an osm file)'); +function stop(msg) { + console.error(msg); + process.exit(-1); +} + +if (!argv.output || typeof(argv.output) != 'string') stop('--output argument required (path to a new file or the keyword "stdout")'); +if (!argv.input || typeof(argv.input) != 'string') stop('--input argument required (path to an osm file)'); var reader = new osmium.Reader(argv.input); diff --git a/package.json b/package.json index d496fcd..f2cd1de 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "contributors": [ "Jochen Topf <joto>" ], - "version": "0.1.0", + "version": "0.1.1", "main": "./lib/osmium.js", "bugs": { "email": "d...@mapbox.com", @@ -23,14 +23,25 @@ "type": "git", "url": "git://github.com/osmcode/node-osmium.git" }, - "licenses": [ { "type": "Boost" } ], + "binary": { + "module_name": "osmium", + "module_path": "./lib", + "remote_uri": "http://node-osmium.s3.amazonaws.com", + "template": "{module_name}-v{major}.{minor}.{patch}-{node_abi}-{platform}-{arch}.tar.gz" + }, + "dependencies": { + "node-pre-gyp": "~0.1.4" + }, + "bundledDependencies":["node-pre-gyp"], "devDependencies": { "mocha": "*" }, + "licenses": [ { "type": "Boost" } ], "engines": { "node": ">= 0.6.13 < 0.11.0" }, "scripts": { + "install": "node-pre-gyp rebuild", "test": "mocha -R spec" } } diff --git a/src/buffer.hpp b/src/buffer.hpp index 43c17db..ccb28a1 100644 --- a/src/buffer.hpp +++ b/src/buffer.hpp @@ -1,7 +1,10 @@ +// c++11 +#include <sstream> + // v8 #include <v8.h> -// node +// node.js #include <node.h> #include <node_version.h> #include <node_object_wrap.h> @@ -21,8 +24,8 @@ namespace node_osmium { static Persistent<FunctionTemplate> constructor; static void Initialize(Handle<Object> target); - static Handle<Value> New(Arguments const& args); - static Handle<Value> dump(Arguments const& args); + static Handle<Value> New(const Arguments& args); + static Handle<Value> dump(const Arguments& args); Buffer(reader_ptr reader); void _ref() { Ref(); diff --git a/src/file.hpp b/src/file_wrap.cpp similarity index 59% rename from src/file.hpp rename to src/file_wrap.cpp index b2b10eb..c3abc55 100644 --- a/src/file.hpp +++ b/src/file_wrap.cpp @@ -1,71 +1,24 @@ -#include <memory> -#include <string> - -// v8 -#include <v8.h> - -// node -#include <node.h> -#include <node_version.h> -#include <node_object_wrap.h> - -// osmium -#include <osmium/io/file.hpp> - -using namespace v8; +#include "file_wrap.hpp" namespace node_osmium { - typedef std::shared_ptr<osmium::io::File> file_ptr; - - class File : public node::ObjectWrap { - - public: - - static Persistent<FunctionTemplate> constructor; - static void Initialize(Handle<Object> target); - static Handle<Value> New(Arguments const& args); - - File(const std::string& filename = "", const std::string& format = ""); - - void _ref() { - Ref(); - } - - void _unref() { - Unref(); - } - - file_ptr get() { - return this_; - } - - private: - - ~File() { - } - - file_ptr this_; - - }; - - Persistent<FunctionTemplate> File::constructor; + Persistent<FunctionTemplate> FileWrap::constructor; - void File::Initialize(Handle<Object> target) { + void FileWrap::Initialize(Handle<Object> target) { HandleScope scope; - constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(File::New)); + constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(FileWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); constructor->SetClassName(String::NewSymbol("File")); target->Set(String::NewSymbol("File"), constructor->GetFunction()); } - File::File(const std::string& filename, const std::string& format) : + FileWrap::FileWrap(const std::string& filename, const std::string& format) : ObjectWrap(), this_(std::make_shared<osmium::io::File>(filename, format)) { } - Handle<Value> File::New(Arguments const& args) { + Handle<Value> FileWrap::New(const Arguments& args) { HandleScope scope; if (!args.IsConstructCall()) { return ThrowException(Exception::Error(String::New("Cannot call constructor as function, you need to use 'new' keyword"))); @@ -89,10 +42,10 @@ namespace node_osmium { } format = *String::Utf8Value(args[1]); } - File* q = new File(filename, format); + FileWrap* q = new FileWrap(filename, format); q->Wrap(args.This()); return args.This(); - } catch (std::exception const& ex) { + } catch (const std::exception& ex) { return ThrowException(Exception::TypeError(String::New(ex.what()))); } return Undefined(); diff --git a/src/file_wrap.hpp b/src/file_wrap.hpp new file mode 100644 index 0000000..6a521c6 --- /dev/null +++ b/src/file_wrap.hpp @@ -0,0 +1,59 @@ +#ifndef FILE_WRAP_HPP +#define FILE_WRAP_HPP + +// c++11 +#include <exception> +#include <memory> +#include <string> + +// v8 +#include <v8.h> + +// node.js +#include <node.h> +#include <node_version.h> +#include <node_object_wrap.h> + +// osmium +#include <osmium/io/file.hpp> + +using namespace v8; + +namespace node_osmium { + + typedef std::shared_ptr<osmium::io::File> file_ptr; + + class FileWrap : public node::ObjectWrap { + + public: + + static Persistent<FunctionTemplate> constructor; + static void Initialize(Handle<Object> target); + static Handle<Value> New(const Arguments& args); + + FileWrap(const std::string& filename = "", const std::string& format = ""); + + void _ref() { + Ref(); + } + + void _unref() { + Unref(); + } + + file_ptr get() { + return this_; + } + + private: + + ~FileWrap() { + } + + file_ptr this_; + + }; + +} // namespace node_osmium + +#endif // FILE_WRAP_HPP diff --git a/src/handler.cpp b/src/handler.cpp new file mode 100644 index 0000000..77d52c9 --- /dev/null +++ b/src/handler.cpp @@ -0,0 +1,170 @@ + +#include "handler.hpp" +#include "osm_node_wrap.hpp" +#include "osm_way_wrap.hpp" +#include "osm_relation_wrap.hpp" + +namespace node_osmium { + + Persistent<FunctionTemplate> JSHandler::constructor; + + void JSHandler::Initialize(Handle<Object> target) { + HandleScope scope; + constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(JSHandler::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Handler")); + NODE_SET_PROTOTYPE_METHOD(constructor, "on", on); + NODE_SET_PROTOTYPE_METHOD(constructor, "options", options); + target->Set(String::NewSymbol("Handler"), constructor->GetFunction()); + } + + JSHandler::JSHandler() : + ObjectWrap(), + node_callback_for_tagged_only(false), + done_cb() { + done_cb.Clear(); + } + + JSHandler::~JSHandler() { + if (!done_cb.IsEmpty()) { + done_cb.Dispose(); + } + if (!node_cb.IsEmpty()) { + node_cb.Dispose(); + } + if (!way_cb.IsEmpty()) { + way_cb.Dispose(); + } + if (!relation_cb.IsEmpty()) { + relation_cb.Dispose(); + } + } + + Handle<Value> JSHandler::New(const Arguments& args) { + HandleScope scope; + if (args[0]->IsExternal()) { + Local<External> ext = Local<External>::Cast(args[0]); + void* ptr = ext->Value(); + JSHandler* b = static_cast<JSHandler*>(ptr); + b->Wrap(args.This()); + return args.This(); + } else { + JSHandler* h = new JSHandler(); + h->Wrap(args.This()); + return args.This(); + } + return Undefined(); + } + + Handle<Value> JSHandler::options(const Arguments& args) { + if (args.Length() == 1) { + if (args[0]->IsObject()) { + Local<Value> tagged_nodes_only = args[0]->ToObject()->Get(String::New("tagged_nodes_only")); + if (tagged_nodes_only->IsBoolean()) { + JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(args.This()); + handler->node_callback_for_tagged_only = tagged_nodes_only->BooleanValue(); + } + } + } + return Undefined(); + } + + Handle<Value> JSHandler::on(const Arguments& args) { + HandleScope scope; + if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsFunction()) { + return ThrowException(Exception::TypeError(String::New("please provide an event name and callback function"))); + } + std::string callback_name = *String::Utf8Value(args[0]->ToString()); + Local<Function> callback = Local<Function>::Cast(args[1]); + if (callback->IsNull() || callback->IsUndefined()) { + return ThrowException(Exception::TypeError(String::New("please provide a valid callback function for second arg"))); + } + JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(args.This()); + if (callback_name == "node") { + if (!handler->node_cb.IsEmpty()) { + handler->node_cb.Dispose(); + } + handler->node_cb = Persistent<Function>::New(callback); + } else if (callback_name == "way") { + if (!handler->way_cb.IsEmpty()) { + handler->way_cb.Dispose(); + } + handler->way_cb = Persistent<Function>::New(callback); + } else if (callback_name == "relation") { + if (!handler->relation_cb.IsEmpty()) { + handler->relation_cb.Dispose(); + } + handler->relation_cb = Persistent<Function>::New(callback); + } else if (callback_name == "done") { + if (!handler->done_cb.IsEmpty()) { + handler->done_cb.Dispose(); + } + handler->done_cb = Persistent<Function>::New(callback); + } + return scope.Close(Undefined()); + } + + void JSHandler::dispatch_object(const osmium::io::InputIterator<osmium::io::Reader, osmium::Object>& it) { + HandleScope scope; + switch (it->type()) { + case osmium::item_type::node: + if (!node_cb.IsEmpty() && (!node_callback_for_tagged_only || !it->tags().empty())) { + const int argc = 1; + + Handle<Value> ext = External::New(new OSMNodeWrap(it)); + Local<Object> obj = OSMNodeWrap::constructor->GetFunction()->NewInstance(1, &ext); + Local<Value> argv[argc] = { obj }; + + TryCatch trycatch; + Handle<Value> v = node_cb->Call(Context::GetCurrent()->Global(), argc, argv); + if (v.IsEmpty()) { + Handle<Value> exception = trycatch.Exception(); + String::AsciiValue exception_str(exception); + printf("Exception: %s\n", *exception_str); + exit(1); + } + } + break; + case osmium::item_type::way: + if (!way_cb.IsEmpty()) { + const int argc = 1; + + Handle<Value> ext = External::New(new OSMWayWrap(it)); + Local<Object> obj = OSMWayWrap::constructor->GetFunction()->NewInstance(1, &ext); + Local<Value> argv[argc] = { obj }; + + TryCatch trycatch; + Handle<Value> v = way_cb->Call(Context::GetCurrent()->Global(), argc, argv); + if (v.IsEmpty()) { + Handle<Value> exception = trycatch.Exception(); + String::AsciiValue exception_str(exception); + printf("Exception: %s\n", *exception_str); + exit(1); + } + } + break; + case osmium::item_type::relation: + if (!relation_cb.IsEmpty()) { + const int argc = 1; + + Handle<Value> ext = External::New(new OSMRelationWrap(it)); + Local<Object> obj = OSMRelationWrap::constructor->GetFunction()->NewInstance(1, &ext); + Local<Value> argv[argc] = { obj }; + + TryCatch trycatch; + Handle<Value> v = relation_cb->Call(Context::GetCurrent()->Global(), argc, argv); + if (v.IsEmpty()) { + Handle<Value> exception = trycatch.Exception(); + String::AsciiValue exception_str(exception); + printf("Exception: %s\n", *exception_str); + exit(1); + } + } + break; + default: + break; + } + } + +} // namespace node_osmium + diff --git a/src/handler.hpp b/src/handler.hpp index d997804..351f319 100644 --- a/src/handler.hpp +++ b/src/handler.hpp @@ -1,11 +1,10 @@ // c++11 -#include <memory> -#include <iostream> +#include <string> // v8 #include <v8.h> -// node +// node.js #include <node.h> #include <node_version.h> #include <node_object_wrap.h> @@ -14,6 +13,8 @@ // osmium #include <osmium/handler.hpp> #include <osmium/osm.hpp> +#include <osmium/io/input_iterator.hpp> +#include <osmium/io/reader.hpp> #include <osmium/geom/wkb.hpp> #include <osmium/geom/wkt.hpp> @@ -21,15 +22,15 @@ namespace node_osmium { using namespace v8; - class JSHandler : public node::ObjectWrap, public osmium::handler::Handler { + class JSHandler : public node::ObjectWrap { public: static Persistent<FunctionTemplate> constructor; static void Initialize(Handle<Object> target); - static Handle<Value> New(Arguments const& args); - static Handle<Value> on(Arguments const& args); - static Handle<Value> options(Arguments const& args); + static Handle<Value> New(const Arguments& args); + static Handle<Value> on(const Arguments& args); + static Handle<Value> options(const Arguments& args); JSHandler(); void _ref() { @@ -40,163 +41,7 @@ namespace node_osmium { Unref(); } - void node(const osmium::Node& node) { - HandleScope scope; - if (!node_cb.IsEmpty() && (!node_callback_for_tagged_only || !node.tags().empty())) { - const int argc = 1; - Local<Object> obj = Object::New(); - obj->Set(String::NewSymbol("id"), Number::New(node.id())); - obj->Set(String::NewSymbol("version"), Number::New(node.version())); - obj->Set(String::NewSymbol("visible"), Boolean::New(node.visible())); - obj->Set(String::NewSymbol("changeset"), Number::New(node.changeset())); - obj->Set(String::NewSymbol("timestamp"), Number::New(node.timestamp())); - std::string iso { node.timestamp().to_iso() }; - obj->Set(String::NewSymbol("timestamp_iso"), String::New(iso.c_str())); - obj->Set(String::NewSymbol("uid"), Number::New(node.uid())); - obj->Set(String::NewSymbol("user"), String::New(node.user())); - obj->Set(String::NewSymbol("lon"), Number::New(node.lon())); - obj->Set(String::NewSymbol("lat"), Number::New(node.lat())); - - { - std::string wkb { wkb_factory.create_point(node) }; -#if NODE_VERSION_AT_LEAST(0, 10, 0) - obj->Set(String::NewSymbol("wkb"), node::Buffer::New(wkb.data(), wkb.size())->handle_); -#else - obj->Set(String::NewSymbol("wkb"), node::Buffer::New(const_cast<char*>(wkb.data()), wkb.size())->handle_); -#endif - } - - { - std::string wkt { wkt_factory.create_point(node) }; - obj->Set(String::NewSymbol("wkt"), String::New(wkt.c_str())); - } - - Local<Object> tags = Object::New(); - for (auto& tag : node.tags()) { - tags->Set(String::NewSymbol(tag.key()), String::New(tag.value())); - } - obj->Set(String::NewSymbol("tags"), tags); - - Local<Value> argv[argc] = { obj }; - - TryCatch trycatch; - Handle<Value> v = node_cb->Call(Context::GetCurrent()->Global(), argc, argv); - if (v.IsEmpty()) { - Handle<Value> exception = trycatch.Exception(); - String::AsciiValue exception_str(exception); - printf("Exception: %s\n", *exception_str); - exit(1); - } - } - } - - void way(const osmium::Way& way) { - HandleScope scope; - if (!way_cb.IsEmpty()) { - const int argc = 1; - Local<Object> obj = Object::New(); - obj->Set(String::NewSymbol("id"), Number::New(way.id())); - obj->Set(String::NewSymbol("version"), Number::New(way.version())); - obj->Set(String::NewSymbol("visible"), Boolean::New(way.visible())); - obj->Set(String::NewSymbol("changeset"), Number::New(way.changeset())); - obj->Set(String::NewSymbol("timestamp"), Number::New(way.timestamp())); - std::string iso { way.timestamp().to_iso() }; - obj->Set(String::NewSymbol("timestamp_iso"), String::New(iso.c_str())); - obj->Set(String::NewSymbol("uid"), Number::New(way.uid())); - obj->Set(String::NewSymbol("user"), String::New(way.user())); - - try { - std::string wkb { wkb_factory.create_linestring(way) }; -#if NODE_VERSION_AT_LEAST(0, 10, 0) - obj->Set(String::NewSymbol("wkb"), node::Buffer::New(wkb.data(), wkb.size())->handle_); -#else - obj->Set(String::NewSymbol("wkb"), node::Buffer::New(const_cast<char*>(wkb.data()), wkb.size())->handle_); -#endif - } catch (osmium::geom::geometry_error&) { - obj->Set(String::NewSymbol("wkb"), Undefined()); - } - - try { - std::string wkt { wkt_factory.create_linestring(way) }; - obj->Set(String::NewSymbol("wkt"), String::New(wkt.c_str())); - } catch (osmium::geom::geometry_error&) { - obj->Set(String::NewSymbol("wkt"), Undefined()); - } - - Local<Object> tags = Object::New(); - for (auto& tag : way.tags()) { - tags->Set(String::NewSymbol(tag.key()), String::New(tag.value())); - } - obj->Set(String::NewSymbol("tags"), tags); - - Local<Array> nodes = Array::New(way.nodes().size()); - int i = 0; - for (auto& node : way.nodes()) { - nodes->Set(i, Number::New(node.ref())); - ++i; - } - obj->Set(String::NewSymbol("nodes"), nodes); - - Local<Value> argv[argc] = { obj }; - - TryCatch trycatch; - Handle<Value> v = way_cb->Call(Context::GetCurrent()->Global(), argc, argv); - if (v.IsEmpty()) { - Handle<Value> exception = trycatch.Exception(); - String::AsciiValue exception_str(exception); - printf("Exception: %s\n", *exception_str); - exit(1); - } - } - } - - void relation(const osmium::Relation& relation) { - HandleScope scope; - if (!relation_cb.IsEmpty()) { - const int argc = 1; - Local<Object> obj = Object::New(); - obj->Set(String::NewSymbol("id"), Number::New(relation.id())); - obj->Set(String::NewSymbol("version"), Number::New(relation.version())); - obj->Set(String::NewSymbol("visible"), Boolean::New(relation.visible())); - obj->Set(String::NewSymbol("changeset"), Number::New(relation.changeset())); - obj->Set(String::NewSymbol("timestamp"), Number::New(relation.timestamp())); - std::string iso { relation.timestamp().to_iso() }; - obj->Set(String::NewSymbol("timestamp_iso"), String::New(iso.c_str())); - obj->Set(String::NewSymbol("uid"), Number::New(relation.uid())); - obj->Set(String::NewSymbol("user"), String::New(relation.user())); - - Local<Object> tags = Object::New(); - for (auto& tag : relation.tags()) { - tags->Set(String::NewSymbol(tag.key()), String::New(tag.value())); - } - obj->Set(String::NewSymbol("tags"), tags); - - Local<Array> members = Array::New(); - int i = 0; - char typec[2] = " "; - for (auto& member : relation.members()) { - Local<Object> jsmember = Object::New(); - typec[0] = osmium::item_type_to_char(member.type()); - jsmember->Set(String::NewSymbol("type"), String::New(typec)); - jsmember->Set(String::NewSymbol("ref"), Number::New(member.ref())); - jsmember->Set(String::NewSymbol("role"), String::New(member.role())); - members->Set(i, jsmember); - ++i; - } - obj->Set(String::NewSymbol("members"), members); - - Local<Value> argv[argc] = { obj }; - - TryCatch trycatch; - Handle<Value> v = relation_cb->Call(Context::GetCurrent()->Global(), argc, argv); - if (v.IsEmpty()) { - Handle<Value> exception = trycatch.Exception(); - String::AsciiValue exception_str(exception); - printf("Exception: %s\n", *exception_str); - exit(1); - } - } - } + void dispatch_object(const osmium::io::InputIterator<osmium::io::Reader, osmium::Object>& it); void done() { if (!done_cb.IsEmpty()) { @@ -214,107 +59,8 @@ namespace node_osmium { private: ~JSHandler(); - osmium::geom::WKBFactory wkb_factory; - osmium::geom::WKTFactory wkt_factory; - }; - - Persistent<FunctionTemplate> JSHandler::constructor; - - void JSHandler::Initialize(Handle<Object> target) { - HandleScope scope; - constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(JSHandler::New)); - constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(String::NewSymbol("Handler")); - NODE_SET_PROTOTYPE_METHOD(constructor, "on", on); - NODE_SET_PROTOTYPE_METHOD(constructor, "options", options); - target->Set(String::NewSymbol("Handler"),constructor->GetFunction()); - } - - JSHandler::JSHandler() : - ObjectWrap(), - node_callback_for_tagged_only(false), - done_cb() { - done_cb.Clear(); - } - - JSHandler::~JSHandler() { - if (!done_cb.IsEmpty()) { - done_cb.Dispose(); - } - if (!node_cb.IsEmpty()) { - node_cb.Dispose(); - } - if (!way_cb.IsEmpty()) { - way_cb.Dispose(); - } - if (!relation_cb.IsEmpty()) { - relation_cb.Dispose(); - } - } - - Handle<Value> JSHandler::New(const Arguments& args) { - HandleScope scope; - if (args[0]->IsExternal()) { - Local<External> ext = Local<External>::Cast(args[0]); - void* ptr = ext->Value(); - JSHandler* b = static_cast<JSHandler*>(ptr); - b->Wrap(args.This()); - return args.This(); - } else { - JSHandler* h = new JSHandler(); - h->Wrap(args.This()); - return args.This(); - } - return Undefined(); - } - Handle<Value> JSHandler::options(const Arguments& args) { - if (args.Length() == 1) { - if (args[0]->IsObject()) { - Local<Value> tagged_nodes_only = args[0]->ToObject()->Get(String::NewSymbol("tagged_nodes_only")); - if (tagged_nodes_only->IsBoolean()) { - JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(args.This()); - handler->node_callback_for_tagged_only = tagged_nodes_only->BooleanValue(); - } - } - } - return Undefined(); - } - - Handle<Value> JSHandler::on(const Arguments& args) { - HandleScope scope; - if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsFunction()) { - return ThrowException(Exception::TypeError(String::New("please provide an event name and callback function"))); - } - Local<String> callback_name = args[0]->ToString(); - Local<Function> callback = Local<Function>::Cast(args[1]); - if (callback->IsNull() || callback->IsUndefined()) { - return ThrowException(Exception::TypeError(String::New("please provide a valid callback function for second arg"))); - } - JSHandler * handler = node::ObjectWrap::Unwrap<JSHandler>(args.This()); - if (callback_name == String::NewSymbol("node")) { - if (!handler->node_cb.IsEmpty()) { - handler->node_cb.Dispose(); - } - handler->node_cb = Persistent<Function>::New(callback); - } else if (callback_name == String::NewSymbol("way")) { - if (!handler->way_cb.IsEmpty()) { - handler->way_cb.Dispose(); - } - handler->way_cb = Persistent<Function>::New(callback); - } else if (callback_name == String::NewSymbol("relation")) { - if (!handler->relation_cb.IsEmpty()) { - handler->relation_cb.Dispose(); - } - handler->relation_cb = Persistent<Function>::New(callback); - } else if (callback_name == String::NewSymbol("done")) { - if (!handler->done_cb.IsEmpty()) { - handler->done_cb.Dispose(); - } - handler->done_cb = Persistent<Function>::New(callback); - } - return scope.Close(Undefined()); - } + }; } // namespace node_osmium diff --git a/src/node_osmium.cpp b/src/node_osmium.cpp index 60a3119..268d67c 100644 --- a/src/node_osmium.cpp +++ b/src/node_osmium.cpp @@ -1,13 +1,20 @@ // v8 #include <v8.h> -// node +// node.js #include <node.h> +// osmium +#include <osmium/geom/wkb.hpp> +#include <osmium/geom/wkt.hpp> + // node-osmium +#include "osm_node_wrap.hpp" +#include "osm_way_wrap.hpp" +#include "osm_relation_wrap.hpp" #include "handler.hpp" -#include "file.hpp" -#include "reader.hpp" +#include "file_wrap.hpp" +#include "reader_wrap.hpp" #include "buffer.hpp" namespace node_osmium { @@ -15,13 +22,19 @@ namespace node_osmium { extern "C" { static void start(v8::Handle<v8::Object> target) { v8::HandleScope scope; + node_osmium::OSMNodeWrap::Initialize(target); + node_osmium::OSMWayWrap::Initialize(target); + node_osmium::OSMRelationWrap::Initialize(target); node_osmium::JSHandler::Initialize(target); - node_osmium::Buffer::Initialize(target); - node_osmium::File::Initialize(target); - node_osmium::Reader::Initialize(target); +// node_osmium::Buffer::Initialize(target); + node_osmium::FileWrap::Initialize(target); + node_osmium::ReaderWrap::Initialize(target); } } + osmium::geom::WKBFactory wkb_factory; + osmium::geom::WKTFactory wkt_factory; + } // namespace node_osmium NODE_MODULE(osmium, node_osmium::start) diff --git a/src/osm_node_wrap.cpp b/src/osm_node_wrap.cpp new file mode 100644 index 0000000..d67b3c9 --- /dev/null +++ b/src/osm_node_wrap.cpp @@ -0,0 +1,78 @@ + +#include <osmium/geom/wkb.hpp> +#include <osmium/geom/wkt.hpp> + +#include "osm_node_wrap.hpp" + +namespace node_osmium { + + extern osmium::geom::WKBFactory wkb_factory; + extern osmium::geom::WKTFactory wkt_factory; + + Persistent<FunctionTemplate> OSMNodeWrap::constructor; + + void OSMNodeWrap::Initialize(Handle<Object> target) { + HandleScope scope; + constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(OSMNodeWrap::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Node")); + NODE_SET_PROTOTYPE_METHOD(constructor, "tags", tags); + NODE_SET_PROTOTYPE_METHOD(constructor, "wkb", wkb); + NODE_SET_PROTOTYPE_METHOD(constructor, "wkt", wkt); + target->Set(String::NewSymbol("Node"), constructor->GetFunction()); + } + + OSMNodeWrap::OSMNodeWrap(const input_iterator& it) : + OSMObjectWrap(it) { + } + + OSMNodeWrap::~OSMNodeWrap() { + } + + Handle<Value> OSMNodeWrap::New(const Arguments& args) { + HandleScope scope; + if (args[0]->IsExternal()) { + Local<External> ext = Local<External>::Cast(args[0]); + void* ptr = ext->Value(); + OSMNodeWrap* node = static_cast<OSMNodeWrap*>(ptr); + node->Wrap(args.This()); + osmium::Node& obj = static_cast<osmium::Node&>(*(node->m_it)); + args.This()->Set(String::New("id"), Number::New(obj.id())); + args.This()->Set(String::New("version"), Number::New(obj.version())); + args.This()->Set(String::New("changeset"), Number::New(obj.changeset())); + args.This()->Set(String::New("visible"), Boolean::New(obj.visible())); + args.This()->Set(String::New("timestamp"), Number::New(obj.timestamp())); + args.This()->Set(String::New("timestamp_iso"), String::New(obj.timestamp().to_iso().c_str(), obj.timestamp().to_iso().size())); + args.This()->Set(String::New("uid"), Number::New(obj.uid())); + args.This()->Set(String::New("user"), String::New(obj.user())); + args.This()->Set(String::New("lon"), Number::New(obj.lon())); + args.This()->Set(String::New("lat"), Number::New(obj.lat())); + + return args.This(); + } else { + return ThrowException(Exception::TypeError(String::New("osmium.Node cannot be created in Javascript"))); + } + return Undefined(); + } + + Handle<Value> OSMNodeWrap::wkb(const Arguments& args) { + HandleScope scope; + osmium::Node& node = static_cast<osmium::Node&>(*(node::ObjectWrap::Unwrap<OSMNodeWrap>(args.This())->m_it)); + + std::string wkb { wkb_factory.create_point(node) }; +#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 + } + + Handle<Value> OSMNodeWrap::wkt(const Arguments& args) { + HandleScope scope; + osmium::Node& node = static_cast<osmium::Node&>(*(node::ObjectWrap::Unwrap<OSMNodeWrap>(args.This())->m_it)); + + std::string wkt { wkt_factory.create_point(node) }; + + return scope.Close(String::New(wkt.c_str())); + } +} // namespace node_osmium diff --git a/src/osm_node_wrap.hpp b/src/osm_node_wrap.hpp new file mode 100644 index 0000000..4994f01 --- /dev/null +++ b/src/osm_node_wrap.hpp @@ -0,0 +1,55 @@ +#ifndef NODE_WRAP_HPP +#define NODE_WRAP_HPP + +// v8 +#include <v8.h> + +// node +#include <node.h> +#include <node_version.h> +#include <node_object_wrap.h> +#include <node_buffer.h> + +// osmium +#include <osmium/osm/node.hpp> +#include <osmium/io/input_iterator.hpp> +#include <osmium/io/reader.hpp> + +#include "osm_object_wrap.hpp" + +using namespace v8; + +namespace node_osmium { + + class OSMNodeWrap : public OSMObjectWrap { + + public: + + static Persistent<FunctionTemplate> constructor; + static void Initialize(Handle<Object> target); + static Handle<Value> New(const Arguments& args); + static Handle<Value> wkb(const Arguments& args); + static Handle<Value> wkt(const Arguments& args); + OSMNodeWrap(const input_iterator&); + + void _ref() { + Ref(); + } + + void _unref() { + Unref(); + } + + osmium::Node& object() { + return static_cast<osmium::Node&>(*m_it); + } + + private: + + ~OSMNodeWrap(); + + }; + +} // namespace node_osmium + +#endif // NODE_WRAP_HPP diff --git a/src/osm_object_wrap.cpp b/src/osm_object_wrap.cpp new file mode 100644 index 0000000..0caacc4 --- /dev/null +++ b/src/osm_object_wrap.cpp @@ -0,0 +1,28 @@ + +#include "osm_object_wrap.hpp" + +namespace node_osmium { + + Handle<Value> OSMObjectWrap::tags(const Arguments& args) { + HandleScope scope; + + osmium::Object& object = *(node::ObjectWrap::Unwrap<OSMObjectWrap>(args.This())->m_it); + + if (args.Length() == 0) { + Local<Object> tags = Object::New(); + for (auto& tag : object.tags()) { + tags->Set(String::New(tag.key()), String::New(tag.value())); + } + return scope.Close(tags); + } else if (args.Length() == 1) { + const char* value = object.tags().get_value_by_key(*String::Utf8Value(args[0])); + if (value) { + return scope.Close(String::New(value)); + } else { + return Undefined(); + } + } + return Undefined(); + } + +} // namespace node_osmium diff --git a/src/osm_object_wrap.hpp b/src/osm_object_wrap.hpp new file mode 100644 index 0000000..805d3e7 --- /dev/null +++ b/src/osm_object_wrap.hpp @@ -0,0 +1,42 @@ +#ifndef OSM_OBJECT_WRAP_HPP +#define OSM_OBJECT_WRAP_HPP + +// v8 +#include <v8.h> + +// node +#include <node.h> +#include <node_version.h> +#include <node_object_wrap.h> +#include <node_buffer.h> + +// osmium +#include <osmium/io/reader.hpp> +#include <osmium/io/input_iterator.hpp> +#include <osmium/osm/object.hpp> + +using namespace v8; + +namespace node_osmium { + + typedef osmium::io::InputIterator<osmium::io::Reader, osmium::Object> input_iterator; + + class OSMObjectWrap : public node::ObjectWrap { + + protected: + + input_iterator m_it; + + public: + + static Handle<Value> tags(const Arguments& args); + + OSMObjectWrap(const input_iterator& it) : + m_it(it) { + } + + }; // class OSMObjectWrap + +} // namespace node_osmium + +#endif // OSM_OBJECT_WRAP_HPP diff --git a/src/osm_relation_wrap.cpp b/src/osm_relation_wrap.cpp new file mode 100644 index 0000000..1c16b16 --- /dev/null +++ b/src/osm_relation_wrap.cpp @@ -0,0 +1,88 @@ + +#include <osm_relation_wrap.hpp> + +namespace node_osmium { + + Persistent<FunctionTemplate> OSMRelationWrap::constructor; + + void OSMRelationWrap::Initialize(Handle<Object> target) { + HandleScope scope; + constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(OSMRelationWrap::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Relation")); + NODE_SET_PROTOTYPE_METHOD(constructor, "tags", tags); + NODE_SET_PROTOTYPE_METHOD(constructor, "members", members); + target->Set(String::NewSymbol("Relation"), constructor->GetFunction()); + } + + OSMRelationWrap::OSMRelationWrap(const input_iterator& it) : + OSMObjectWrap(it) { + } + + OSMRelationWrap::~OSMRelationWrap() { + } + + Handle<Value> OSMRelationWrap::New(const Arguments& args) { + HandleScope scope; + if (args[0]->IsExternal()) { + Local<External> ext = Local<External>::Cast(args[0]); + void* ptr = ext->Value(); + OSMRelationWrap* relation = static_cast<OSMRelationWrap*>(ptr); + relation->Wrap(args.This()); + osmium::Relation& obj = static_cast<osmium::Relation&>(*(relation->m_it)); + args.This()->Set(String::New("id"), Number::New(obj.id())); + args.This()->Set(String::New("version"), Number::New(obj.version())); + args.This()->Set(String::New("changeset"), Number::New(obj.changeset())); + args.This()->Set(String::New("visible"), Boolean::New(obj.visible())); + args.This()->Set(String::New("timestamp"), Number::New(obj.timestamp())); + args.This()->Set(String::New("timestamp_iso"), String::New(obj.timestamp().to_iso().c_str(), obj.timestamp().to_iso().size())); + args.This()->Set(String::New("uid"), Number::New(obj.uid())); + args.This()->Set(String::New("user"), String::New(obj.user())); + return args.This(); + } else { + return ThrowException(Exception::TypeError(String::New("osmium.Relation cannot be created in Javascript"))); + } + return Undefined(); + } + + Handle<Value> OSMRelationWrap::members(const Arguments& args) { + HandleScope scope; + osmium::Relation& relation = static_cast<osmium::Relation&>(*(node::ObjectWrap::Unwrap<OSMRelationWrap>(args.This())->m_it)); + + if (args.Length() == 0) { + Local<Array> members = Array::New(); + int i = 0; + char typec[2] = " "; + for (auto& member : relation.members()) { + Local<Object> jsmember = Object::New(); + typec[0] = osmium::item_type_to_char(member.type()); + jsmember->Set(String::New("type"), String::New(typec)); + jsmember->Set(String::New("ref"), Number::New(member.ref())); + jsmember->Set(String::New("role"), String::New(member.role())); + members->Set(i, jsmember); + ++i; + } + return scope.Close(members); + } else if (args.Length() == 1) { + if (args[0]->IsNumber()) { + int n = static_cast<int>(args[0]->ToNumber()->Value()); + if (n > 0 && n < static_cast<int>(relation.members().size())) { + auto it = relation.members().begin(); + std::advance(it, n); + osmium::RelationMember& member = *it; + Local<Object> jsmember = Object::New(); + char typec[2] = " "; + typec[0] = osmium::item_type_to_char(member.type()); + jsmember->Set(String::New("type"), String::New(typec)); + jsmember->Set(String::New("ref"), Number::New(member.ref())); + jsmember->Set(String::New("role"), String::New(member.role())); + return scope.Close(jsmember); + } + } + } + + return Undefined(); + } + +} // namespace node_osmium + diff --git a/src/osm_relation_wrap.hpp b/src/osm_relation_wrap.hpp new file mode 100644 index 0000000..d65877e --- /dev/null +++ b/src/osm_relation_wrap.hpp @@ -0,0 +1,56 @@ +#ifndef RELATION_WRAP_HPP +#define RELATION_WRAP_HPP + +// c++ +#include <iterator> + +// v8 +#include <v8.h> + +// node +#include <node.h> +#include <node_version.h> +#include <node_object_wrap.h> + +// osmium +#include <osmium/osm/relation.hpp> +#include <osmium/io/input_iterator.hpp> +#include <osmium/io/reader.hpp> + +#include "osm_object_wrap.hpp" + +using namespace v8; + +namespace node_osmium { + + class OSMRelationWrap : public OSMObjectWrap { + + public: + + static Persistent<FunctionTemplate> constructor; + static void Initialize(Handle<Object> target); + static Handle<Value> New(const Arguments& args); + static Handle<Value> members(const Arguments& args); + OSMRelationWrap(const input_iterator&); + + void _ref() { + Ref(); + } + + void _unref() { + Unref(); + } + + osmium::Relation& object() { + return static_cast<osmium::Relation&>(*m_it); + } + + private: + + ~OSMRelationWrap(); + + }; + +} // namespace node_osmium + +#endif // RELATION_WRAP_HPP diff --git a/src/osm_way_wrap.cpp b/src/osm_way_wrap.cpp new file mode 100644 index 0000000..a3a3723 --- /dev/null +++ b/src/osm_way_wrap.cpp @@ -0,0 +1,108 @@ + +#include <osmium/geom/wkb.hpp> +#include <osmium/geom/wkt.hpp> + +#include "osm_way_wrap.hpp" + +namespace node_osmium { + + extern osmium::geom::WKBFactory wkb_factory; + extern osmium::geom::WKTFactory wkt_factory; + + Persistent<FunctionTemplate> OSMWayWrap::constructor; + + void OSMWayWrap::Initialize(Handle<Object> target) { + HandleScope scope; + constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(OSMWayWrap::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Way")); + NODE_SET_PROTOTYPE_METHOD(constructor, "tags", tags); + NODE_SET_PROTOTYPE_METHOD(constructor, "wkb", wkb); + NODE_SET_PROTOTYPE_METHOD(constructor, "wkt", wkt); + NODE_SET_PROTOTYPE_METHOD(constructor, "nodes", nodes); + target->Set(String::NewSymbol("Way"), constructor->GetFunction()); + } + + OSMWayWrap::OSMWayWrap(const input_iterator& it) : + OSMObjectWrap(it) { + } + + OSMWayWrap::~OSMWayWrap() { + } + + Handle<Value> OSMWayWrap::New(const Arguments& args) { + HandleScope scope; + if (args[0]->IsExternal()) { + Local<External> ext = Local<External>::Cast(args[0]); + void* ptr = ext->Value(); + OSMWayWrap* way = static_cast<OSMWayWrap*>(ptr); + way->Wrap(args.This()); + osmium::Way& obj = static_cast<osmium::Way&>(*(way->m_it)); + args.This()->Set(String::New("id"), Number::New(obj.id())); + args.This()->Set(String::New("version"), Number::New(obj.version())); + args.This()->Set(String::New("changeset"), Number::New(obj.changeset())); + args.This()->Set(String::New("visible"), Boolean::New(obj.visible())); + args.This()->Set(String::New("timestamp"), Number::New(obj.timestamp())); + args.This()->Set(String::New("timestamp_iso"), String::New(obj.timestamp().to_iso().c_str(), obj.timestamp().to_iso().size())); + args.This()->Set(String::New("uid"), Number::New(obj.uid())); + args.This()->Set(String::New("user"), String::New(obj.user())); + return args.This(); + } else { + return ThrowException(Exception::TypeError(String::New("osmium.Way cannot be created in Javascript"))); + } + return Undefined(); + } + + Handle<Value> OSMWayWrap::wkb(const Arguments& args) { + HandleScope scope; + osmium::Way& way = static_cast<osmium::Way&>(*(node::ObjectWrap::Unwrap<OSMWayWrap>(args.This())->m_it)); + + try { + std::string wkb { wkb_factory.create_linestring(way) }; +#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 (osmium::geom::geometry_error&) { + return scope.Close(Undefined()); + } + } + + Handle<Value> OSMWayWrap::wkt(const Arguments& args) { + HandleScope scope; + osmium::Way& way = static_cast<osmium::Way&>(*(node::ObjectWrap::Unwrap<OSMWayWrap>(args.This())->m_it)); + + try { + std::string wkt { wkt_factory.create_linestring(way) }; + return scope.Close(String::New(wkt.c_str())); + } catch (osmium::geom::geometry_error&) { + return scope.Close(Undefined()); + } + } + + Handle<Value> OSMWayWrap::nodes(const Arguments& args) { + HandleScope scope; + osmium::Way& way = static_cast<osmium::Way&>(*(node::ObjectWrap::Unwrap<OSMWayWrap>(args.This())->m_it)); + + if (args.Length() == 0) { + Local<Array> nodes = Array::New(way.nodes().size()); + int i = 0; + for (auto& wn : way.nodes()) { + nodes->Set(i, Number::New(wn.ref())); + ++i; + } + return scope.Close(nodes); + } else if (args.Length() == 1) { + if (args[0]->IsNumber()) { + int n = static_cast<int>(args[0]->ToNumber()->Value()); + if (n > 0 && n < static_cast<int>(way.nodes().size())) { + return scope.Close(Number::New(way.nodes()[n].ref())); + } + } + } + return Undefined(); + } + +} // namespace node_osmium + diff --git a/src/osm_way_wrap.hpp b/src/osm_way_wrap.hpp new file mode 100644 index 0000000..9de530e --- /dev/null +++ b/src/osm_way_wrap.hpp @@ -0,0 +1,55 @@ +#ifndef WAY_WRAP_HPP +#define WAY_WRAP_HPP + +// v8 +#include <v8.h> + +// node +#include <node.h> +#include <node_version.h> +#include <node_object_wrap.h> + +// osmium +#include <osmium/osm/way.hpp> +#include <osmium/io/input_iterator.hpp> +#include <osmium/io/reader.hpp> + +#include "osm_object_wrap.hpp" + +using namespace v8; + +namespace node_osmium { + + class OSMWayWrap : public OSMObjectWrap { + + public: + + static Persistent<FunctionTemplate> constructor; + static void Initialize(Handle<Object> target); + static Handle<Value> New(const Arguments& args); + static Handle<Value> wkb(const Arguments& args); + static Handle<Value> wkt(const Arguments& args); + static Handle<Value> nodes(const Arguments& args); + OSMWayWrap(const input_iterator&); + + void _ref() { + Ref(); + } + + void _unref() { + Unref(); + } + + osmium::Way& object() { + return static_cast<osmium::Way&>(*m_it); + } + + private: + + ~OSMWayWrap(); + + }; + +} // namespace node_osmium + +#endif // WAY_WRAP_HPP diff --git a/src/reader.hpp b/src/reader_wrap.cpp similarity index 58% rename from src/reader.hpp rename to src/reader_wrap.cpp index 4d93d8b..73f6c2b 100644 --- a/src/reader.hpp +++ b/src/reader_wrap.cpp @@ -1,71 +1,15 @@ -// c++11 -#include <memory> -#include <sstream> - -// v8 -#include <v8.h> - -// node -#include <node.h> -#include <node_version.h> -#include <node_object_wrap.h> - -// osmium -#include <osmium/io/any_input.hpp> // bring in XML and PBF support -#include <osmium/io/reader.hpp> -#include <osmium/visitor.hpp> -#include <osmium/handler/node_locations_for_ways.hpp> -#include <osmium/index/map/dummy.hpp> -#include <osmium/index/map/stl_map.hpp> -#include <osmium/index/map/sparse_table.hpp> - -typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type; -typedef osmium::index::map::SparseTable<osmium::unsigned_object_id_type, osmium::Location> index_pos_type; -typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type; - -using namespace v8; +#include "reader_wrap.hpp" +#include "file_wrap.hpp" +#include "handler.hpp" namespace node_osmium { - typedef std::shared_ptr<osmium::io::Reader> reader_ptr; - - class Reader : public node::ObjectWrap { - - public: - - static Persistent<FunctionTemplate> constructor; - static void Initialize(Handle<Object> target); - static Handle<Value> New(Arguments const& args); - static Handle<Value> header(Arguments const& args); - static Handle<Value> apply(Arguments const& args); - static Handle<Value> close(Arguments const& args); - Reader(osmium::io::File& infile, osmium::osm_entity::flags entities); - - void _ref() { - Ref(); - } - - void _unref() { - Unref(); - } - - reader_ptr get() { - return this_; - } - - private: + Persistent<FunctionTemplate> ReaderWrap::constructor; - ~Reader(); - reader_ptr this_; - osmium::io::Header header_; - }; - - Persistent<FunctionTemplate> Reader::constructor; - - void Reader::Initialize(Handle<Object> target) { + void ReaderWrap::Initialize(Handle<Object> target) { HandleScope scope; - constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Reader::New)); + constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(ReaderWrap::New)); constructor->InstanceTemplate()->SetInternalFieldCount(1); constructor->SetClassName(String::NewSymbol("Reader")); NODE_SET_PROTOTYPE_METHOD(constructor, "header", header); @@ -74,15 +18,15 @@ namespace node_osmium { target->Set(String::NewSymbol("Reader"), constructor->GetFunction()); } - Reader::Reader(osmium::io::File& file, osmium::osm_entity::flags entities) : + ReaderWrap::ReaderWrap(osmium::io::File& file, osmium::osm_entity::flags entities) : ObjectWrap(), this_(std::make_shared<osmium::io::Reader>(file, entities)), header_(this_->header()) { } - Reader::~Reader() { } + ReaderWrap::~ReaderWrap() { } - Handle<Value> Reader::New(const Arguments& args) { + Handle<Value> ReaderWrap::New(const Arguments& args) { HandleScope scope; if (!args.IsConstructCall()) { return ThrowException(Exception::Error(String::New("Cannot call constructor as function, you need to use 'new' keyword"))); @@ -99,17 +43,17 @@ namespace node_osmium { read_which_entities = osmium::osm_entity::flags::nothing; Local<Object> options = args[1]->ToObject(); - Local<Value> want_nodes = options->Get(String::NewSymbol("node")); + Local<Value> want_nodes = options->Get(String::New("node")); if (want_nodes->IsBoolean() && want_nodes->BooleanValue()) { read_which_entities |= osmium::osm_entity::flags::node; } - Local<Value> want_ways = options->Get(String::NewSymbol("way")); + Local<Value> want_ways = options->Get(String::New("way")); if (want_ways->IsBoolean() && want_ways->BooleanValue()) { read_which_entities |= osmium::osm_entity::flags::way; } - Local<Value> want_relations = options->Get(String::NewSymbol("relation")); + Local<Value> want_relations = options->Get(String::New("relation")); if (want_relations->IsBoolean() && want_relations->BooleanValue()) { read_which_entities |= osmium::osm_entity::flags::relation; } @@ -117,41 +61,41 @@ namespace node_osmium { } if (args[0]->IsString()) { osmium::io::File file(*String::Utf8Value(args[0])); - Reader* q = new Reader(file, read_which_entities); + ReaderWrap* q = new ReaderWrap(file, read_which_entities); q->Wrap(args.This()); return args.This(); - } else if (args[0]->IsObject() && File::constructor->HasInstance(args[0]->ToObject())) { + } else if (args[0]->IsObject() && FileWrap::constructor->HasInstance(args[0]->ToObject())) { Local<Object> file_obj = args[0]->ToObject(); - File* file_wrap = node::ObjectWrap::Unwrap<File>(file_obj); - Reader* q = new Reader(*(file_wrap->get()), read_which_entities); + FileWrap* file_wrap = node::ObjectWrap::Unwrap<FileWrap>(file_obj); + ReaderWrap* q = new ReaderWrap(*(file_wrap->get()), read_which_entities); q->Wrap(args.This()); return args.This(); } else { return ThrowException(Exception::TypeError(String::New("please provide a File object or string for the first argument when creating a Reader"))); } - } catch (std::exception const& ex) { + } catch (const std::exception& ex) { return ThrowException(Exception::TypeError(String::New(ex.what()))); } return Undefined(); } - Handle<Value> Reader::header(const Arguments& args) { + Handle<Value> ReaderWrap::header(const Arguments& args) { HandleScope scope; Local<Object> obj = Object::New(); - Reader* reader = node::ObjectWrap::Unwrap<Reader>(args.This()); - osmium::io::Header const& header = reader->header_; - obj->Set(String::NewSymbol("generator"), String::New(header.get("generator").c_str())); - osmium::Box const& bounds = header.box(); + ReaderWrap* reader = node::ObjectWrap::Unwrap<ReaderWrap>(args.This()); + const osmium::io::Header& header = reader->header_; + obj->Set(String::New("generator"), String::New(header.get("generator").c_str())); + const osmium::Box& bounds = header.box(); Local<Array> arr = Array::New(4); - arr->Set(0,Number::New(bounds.bottom_left().lon())); - arr->Set(1,Number::New(bounds.bottom_left().lat())); - arr->Set(2,Number::New(bounds.top_right().lon())); - arr->Set(3,Number::New(bounds.top_right().lat())); - obj->Set(String::NewSymbol("bounds"),arr); + arr->Set(0, Number::New(bounds.bottom_left().lon())); + arr->Set(1, Number::New(bounds.bottom_left().lat())); + arr->Set(2, Number::New(bounds.top_right().lon())); + arr->Set(3, Number::New(bounds.top_right().lat())); + obj->Set(String::New("bounds"), arr); return scope.Close(obj); } - Handle<Value> Reader::apply(const Arguments& args) { + Handle<Value> ReaderWrap::apply(const Arguments& args) { HandleScope scope; if (args.Length() != 1 && args.Length() != 2) { @@ -171,31 +115,47 @@ namespace node_osmium { if (!args[1]->IsObject()) { return ThrowException(Exception::TypeError(String::New("second argument must be 'option' object"))); } - Local<Value> wlh = args[1]->ToObject()->Get(String::NewSymbol("with_location_handler")); + Local<Value> wlh = args[1]->ToObject()->Get(String::New("with_location_handler")); if (wlh->BooleanValue()) { with_location_handler = true; } } JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(obj); - Reader* reader = node::ObjectWrap::Unwrap<Reader>(args.This()); + ReaderWrap* reader = node::ObjectWrap::Unwrap<ReaderWrap>(args.This()); reader_ptr r_ptr = reader->get(); if (with_location_handler) { index_pos_type index_pos; index_neg_type index_neg; location_handler_type location_handler(index_pos, index_neg); - osmium::apply(*r_ptr, location_handler, *handler); + + osmium::io::InputIterator<osmium::io::Reader, osmium::Object> it(*r_ptr); + osmium::io::InputIterator<osmium::io::Reader, osmium::Object> end; + + for (; it != end; ++it) { + osmium::apply_item(*it, location_handler); + handler->dispatch_object(it); + } + + handler->done(); } else { - osmium::apply(*r_ptr, *handler); + osmium::io::InputIterator<osmium::io::Reader, osmium::Object> it(*r_ptr); + osmium::io::InputIterator<osmium::io::Reader, osmium::Object> end; + + for (; it != end; ++it) { + handler->dispatch_object(it); + } + + handler->done(); } return Undefined(); } - Handle<Value> Reader::close(const Arguments& args) { + Handle<Value> ReaderWrap::close(const Arguments& args) { HandleScope scope; - Reader* reader = node::ObjectWrap::Unwrap<Reader>(args.This()); + ReaderWrap* reader = node::ObjectWrap::Unwrap<ReaderWrap>(args.This()); reader_ptr r_ptr = reader->get(); r_ptr->close(); return Undefined(); diff --git a/src/reader_wrap.hpp b/src/reader_wrap.hpp new file mode 100644 index 0000000..2c4f757 --- /dev/null +++ b/src/reader_wrap.hpp @@ -0,0 +1,68 @@ +#ifndef READER_WRAP_HPP +#define READER_WRAP_HPP + +// c++11 +#include <exception> +#include <memory> + +// v8 +#include <v8.h> + +// node.js +#include <node.h> +#include <node_version.h> +#include <node_object_wrap.h> + +// osmium +#include <osmium/io/any_input.hpp> +#include <osmium/io/input_iterator.hpp> +#include <osmium/visitor.hpp> +#include <osmium/handler/node_locations_for_ways.hpp> +#include <osmium/index/map/dummy.hpp> +#include <osmium/index/map/stl_map.hpp> +#include <osmium/index/map/sparse_table.hpp> + +typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type; +typedef osmium::index::map::SparseTable<osmium::unsigned_object_id_type, osmium::Location> index_pos_type; +typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type; + +using namespace v8; + +namespace node_osmium { + + typedef std::shared_ptr<osmium::io::Reader> reader_ptr; + + class ReaderWrap : public node::ObjectWrap { + + public: + + static Persistent<FunctionTemplate> constructor; + static void Initialize(Handle<Object> target); + static Handle<Value> New(const Arguments& args); + static Handle<Value> header(const Arguments& args); + static Handle<Value> apply(const Arguments& args); + static Handle<Value> close(const Arguments& args); + ReaderWrap(osmium::io::File& infile, osmium::osm_entity::flags entities); + + void _ref() { + Ref(); + } + + void _unref() { + Unref(); + } + + reader_ptr get() { + return this_; + } + + private: + + ~ReaderWrap(); + reader_ptr this_; + osmium::io::Header header_; + }; + +} // namespace node_osmium + +#endif // READER_WRAP_HPP diff --git a/test/osmium.test.js b/test/osmium.test.js index 2906bbd..40659f2 100644 --- a/test/osmium.test.js +++ b/test/osmium.test.js @@ -36,7 +36,7 @@ describe('osmium', function() { var reader2 = new osmium.Reader(file2); nodes = 0; handler.on('done',function() { - assert.equal(nodes,1525); + assert.equal(nodes, 1525); done(); }); reader2.apply(handler); @@ -44,8 +44,8 @@ describe('osmium', function() { it('should be able to get node data from handler parameter', function(done) { var handler = new osmium.Handler(); - var nodes = 0, ways = 0; - handler.on('node',function(node) { + var nodes = 0, ways = 0, relations = 0; + handler.on('node', function(node) { if (nodes == 0) { assert.equal(node.id, 50031066); assert.equal(node.lon, -120.1891610); @@ -54,16 +54,31 @@ describe('osmium', function() { assert.equal(node.id, 50031085); assert.equal(node.lon, -120.1929190); } + if (node.id == 1564464078) { + assert.equal(node.changeset, 10220832); + assert.equal(node.tags().amenity, 'pub'); + assert.equal(node.tags('name'), 'Old Schoolhouse Brewery'); + } ++nodes; }); - handler.on('way',function(way) { + handler.on('way', function(way) { if (ways == 0) { assert.equal(way.id, 6091729); + assert.equal(way.nodes(1), 50253602); + assert.deepEqual(way.nodes(), [50253600, 50253602, 50137292, 50137371, 50253605, 50253608]); } ++ways; }); - handler.on('done',function() { - assert.equal(nodes,1525); + handler.on('relation', function(relation) { + if (relations == 0) { + assert.equal(relation.id, 237891); + assert.deepEqual(relation.members()[0], ['w', 40512249, 'outer']); + assert.deepEqual(relation.members(3), ['w', 40512257, 'inner']); + } + ++relations; + }); + handler.on('done', function() { + assert.equal(nodes, 1525); done(); }); var reader = new osmium.Reader(__dirname+"/data/winthrop.osm", { 'node': true, 'way': true }); -- 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