Skip to content

Commit 38ccfdf

Browse files
committed
N-API mapnik.Map.queryPoint mapnik.Map.queryMapPoint (WIP) [skip ci]
1 parent 4e7e611 commit 38ccfdf

File tree

4 files changed

+330
-358
lines changed

4 files changed

+330
-358
lines changed

src/mapnik_featureset.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
#include <napi.h>
55

66
using featureset_ptr = mapnik::featureset_ptr;
7+
namespace detail { struct AsyncQueryPoint;}
78

89
class Featureset : public Napi::ObjectWrap<Featureset>
910
{
1011
friend class Datasource;
12+
friend struct detail::AsyncQueryPoint;
1113
public:
1214
// initialiser
1315
static Napi::Object Initialize(Napi::Env env, Napi::Object exports);

src/mapnik_map.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class Map : public Napi::ObjectWrap<Map>
8080
private:
8181
inline bool acquire() {return not_in_use_.fetch_and(0);}
8282
inline void release() {not_in_use_ = 1;}
83-
83+
Napi::Value query_point_impl(Napi::CallbackInfo const& info, bool geo_coords);
8484
static Napi::FunctionReference constructor;
8585
map_ptr map_;
8686
std::atomic<int> not_in_use_{1};

src/mapnik_map_query_point.cpp

+126-156
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,102 @@
11
#include "mapnik_map.hpp"
2+
#include "mapnik_featureset.hpp"
3+
#include <mapnik/map.hpp>
4+
#include <mapnik/layer.hpp>
5+
6+
namespace detail {
7+
8+
struct AsyncQueryPoint : Napi::AsyncWorker
9+
{
10+
using Base = Napi::AsyncWorker;
11+
AsyncQueryPoint(map_ptr const& map, double x, double y, int layer_idx, bool geo_coords, Napi::Function const& callback)
12+
: Base(callback),
13+
map_(map),
14+
x_(x),
15+
y_(y),
16+
layer_idx_(layer_idx),
17+
geo_coords_(geo_coords) {}
18+
19+
void Execute() override
20+
{
21+
try
22+
{
23+
std::vector<mapnik::layer> const& layers = map_->layers();
24+
if (layer_idx_ >= 0)
25+
{
26+
mapnik::featureset_ptr fs;
27+
if (geo_coords_)
28+
{
29+
fs = map_->query_point(layer_idx_, x_, y_);
30+
}
31+
else
32+
{
33+
fs = map_->query_map_point(layer_idx_, x_, y_);
34+
}
35+
mapnik::layer const& lyr = layers[layer_idx_];
36+
featuresets_.insert(std::make_pair(lyr.name(),fs));
37+
}
38+
else
39+
{
40+
// query all layers
41+
unsigned idx = 0;
42+
for (mapnik::layer const& lyr : layers)
43+
{
44+
mapnik::featureset_ptr fs;
45+
if (geo_coords_)
46+
{
47+
fs = map_->query_point(idx, x_, y_);
48+
}
49+
else
50+
{
51+
fs = map_->query_map_point(idx, x_, y_);
52+
}
53+
featuresets_.insert(std::make_pair(lyr.name(),fs));
54+
++idx;
55+
}
56+
}
57+
}
58+
catch (std::exception const& ex)
59+
{
60+
SetError(ex.what());
61+
}
62+
}
63+
64+
std::vector<napi_value> GetResult(Napi::Env env) override
65+
{
66+
std::size_t num_result = featuresets_.size();
67+
if (num_result >= 1)
68+
{
69+
Napi::Array arr = Napi::Array::New(env, num_result);
70+
typedef std::map<std::string,mapnik::featureset_ptr> fs_itr;
71+
fs_itr::iterator it = featuresets_.begin();
72+
fs_itr::iterator end = featuresets_.end();
73+
unsigned idx = 0;
74+
for (; it != end; ++it)
75+
{
76+
Napi::Object obj = Napi::Object::New(env);
77+
obj.Set("layer", Napi::String::New(env, it->first));
78+
Napi::Value arg = Napi::External<mapnik::featureset_ptr>::New(env, &it->second);
79+
obj.Set("featureset", Featureset::constructor.New({arg}));
80+
arr.Set(idx, obj);
81+
++idx;
82+
}
83+
featuresets_.clear();
84+
return { env.Undefined(), arr };
85+
}
86+
return Base::GetResult(env);
87+
}
88+
89+
private:
90+
map_ptr map_;
91+
double x_;
92+
double y_;
93+
int layer_idx_;
94+
bool geo_coords_;
95+
std::map<std::string, mapnik::featureset_ptr> featuresets_;
96+
};
97+
98+
}
299

3-
/*
4-
typedef struct {
5-
uv_work_t request;
6-
Map *m;
7-
std::map<std::string,mapnik::featureset_ptr> featuresets;
8-
int layer_idx;
9-
bool geo_coords;
10-
double x;
11-
double y;
12-
bool error;
13-
std::string error_name;
14-
Napi::FunctionReference cb;
15-
} query_map_baton_t;
16-
*/
17100

18101
/**
19102
* Query a `Mapnik#Map` object to retrieve layer and feature data based on an
@@ -48,8 +131,7 @@ typedef struct {
48131

49132
Napi::Value Map::queryMapPoint(Napi::CallbackInfo const& info)
50133
{
51-
//abstractQueryPoint(info,false);
52-
return info.Env().Undefined();
134+
return query_point_impl(info,false);
53135
}
54136

55137
/**
@@ -85,25 +167,25 @@ Napi::Value Map::queryMapPoint(Napi::CallbackInfo const& info)
85167

86168
Napi::Value Map::queryPoint(Napi::CallbackInfo const& info)
87169
{
88-
//abstractQueryPoint(info,true);
89-
return info.Env().Undefined();
170+
return query_point_impl(info, true);
90171
}
91-
/*
92-
Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coords)
172+
173+
Napi::Value Map::query_point_impl(Napi::CallbackInfo const& info, bool geo_coords)
93174
{
175+
Napi::Env env = info.Env();
94176
Napi::HandleScope scope(env);
95177
if (info.Length() < 3)
96178
{
97-
Napi::Error::New(env, "requires at least three arguments, a x,y query and a callback").ThrowAsJavaScriptException();
98-
179+
Napi::Error::New(env, "requires at least three arguments, a x,y query and a callback")
180+
.ThrowAsJavaScriptException();
99181
return env.Undefined();
100182
}
101183

102-
double x,y;
184+
double x;
185+
double y;
103186
if (!info[0].IsNumber() || !info[1].IsNumber())
104187
{
105188
Napi::TypeError::New(env, "x,y arguments must be numbers").ThrowAsJavaScriptException();
106-
107189
return env.Undefined();
108190
}
109191
else
@@ -112,36 +194,34 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
112194
y = info[1].As<Napi::Number>().DoubleValue();
113195
}
114196

115-
Map* m = info.Holder().Unwrap<Map>();
116-
117197
Napi::Object options = Napi::Object::New(env);
118198
int layer_idx = -1;
119199

120200
if (info.Length() > 3)
121201
{
122202
// options object
123-
if (!info[2].IsObject()) {
203+
if (!info[2].IsObject())
204+
{
124205
Napi::TypeError::New(env, "optional third argument must be an options object").ThrowAsJavaScriptException();
125-
126206
return env.Undefined();
127207
}
128208

129-
options = info[2].ToObject(Napi::GetCurrentContext());
130-
131-
if ((options).Has(Napi::String::New(env, "layer")).FromMaybe(false))
209+
options = info[2].As<Napi::Object>();
210+
if (options.Has("layer"))
132211
{
133-
std::vector<mapnik::layer> const& layers = m->map_->layers();
134-
Napi::Value layer_id = (options).Get(Napi::String::New(env, "layer"));
135-
if (! (layer_id.IsString() || layer_id.IsNumber()) ) {
212+
std::vector<mapnik::layer> const& layers = map_->layers();
213+
Napi::Value layer_id = options.Get("layer");
214+
if (!(layer_id.IsString() || layer_id.IsNumber()) )
215+
{
136216
Napi::TypeError::New(env, "'layer' option required for map query and must be either a layer name(string) or layer index (integer)").ThrowAsJavaScriptException();
137-
138217
return env.Undefined();
139218
}
140219

141-
if (layer_id.IsString()) {
220+
if (layer_id.IsString())
221+
{
142222
bool found = false;
143223
unsigned int idx(0);
144-
std::string layer_name = TOSTR(layer_id);
224+
std::string layer_name = layer_id.As<Napi::String>();
145225
for (mapnik::layer const& lyr : layers)
146226
{
147227
if (lyr.name() == layer_name)
@@ -157,7 +237,6 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
157237
std::ostringstream s;
158238
s << "Layer name '" << layer_name << "' not found";
159239
Napi::TypeError::New(env, s.str().c_str()).ThrowAsJavaScriptException();
160-
161240
return env.Undefined();
162241
}
163242
}
@@ -178,10 +257,11 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
178257
{
179258
s << "no layers found in map";
180259
}
181-
Napi::TypeError::New(env, s.str().c_str()).ThrowAsJavaScriptException();
182-
260+
Napi::TypeError::New(env, s.str()).ThrowAsJavaScriptException();
183261
return env.Undefined();
184-
} else if (layer_idx >= static_cast<int>(layer_num)) {
262+
}
263+
else if (layer_idx >= static_cast<int>(layer_num))
264+
{
185265
std::ostringstream s;
186266
s << "Zero-based layer index '" << layer_idx << "' not valid, ";
187267
if (layer_num > 0)
@@ -192,130 +272,20 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
192272
{
193273
s << "no layers found in map";
194274
}
195-
Napi::TypeError::New(env, s.str().c_str()).ThrowAsJavaScriptException();
196-
275+
Napi::TypeError::New(env, s.str()).ThrowAsJavaScriptException();
197276
return env.Undefined();
198277
}
199278
}
200279
}
201280
}
202-
203281
// ensure function callback
204282
Napi::Value callback = info[info.Length() - 1];
205-
if (!callback->IsFunction()) {
283+
if (!callback.IsFunction())
284+
{
206285
Napi::TypeError::New(env, "last argument must be a callback function").ThrowAsJavaScriptException();
207-
208286
return env.Undefined();
209287
}
210-
211-
query_map_baton_t *closure = new query_map_baton_t();
212-
closure->request.data = closure;
213-
closure->m = m;
214-
closure->x = x;
215-
closure->y = y;
216-
closure->layer_idx = static_cast<std::size_t>(layer_idx);
217-
closure->geo_coords = geo_coords;
218-
closure->error = false;
219-
closure->cb.Reset(callback.As<Napi::Function>());
220-
uv_queue_work(uv_default_loop(), &closure->request, EIO_QueryMap, (uv_after_work_cb)EIO_AfterQueryMap);
221-
m->Ref();
288+
auto * worker = new detail::AsyncQueryPoint(map_, x, y, layer_idx, geo_coords, callback.As<Napi::Function>());
289+
worker->Queue();
222290
return env.Undefined();
223291
}
224-
225-
void Map::EIO_QueryMap(uv_work_t* req)
226-
{
227-
query_map_baton_t *closure = static_cast<query_map_baton_t *>(req->data);
228-
229-
try
230-
{
231-
std::vector<mapnik::layer> const& layers = closure->m->map_->layers();
232-
if (closure->layer_idx >= 0)
233-
{
234-
mapnik::featureset_ptr fs;
235-
if (closure->geo_coords)
236-
{
237-
fs = closure->m->map_->query_point(closure->layer_idx,
238-
closure->x,
239-
closure->y);
240-
}
241-
else
242-
{
243-
fs = closure->m->map_->query_map_point(closure->layer_idx,
244-
closure->x,
245-
closure->y);
246-
}
247-
mapnik::layer const& lyr = layers[closure->layer_idx];
248-
closure->featuresets.insert(std::make_pair(lyr.name(),fs));
249-
}
250-
else
251-
{
252-
// query all layers
253-
unsigned idx = 0;
254-
for (mapnik::layer const& lyr : layers)
255-
{
256-
mapnik::featureset_ptr fs;
257-
if (closure->geo_coords)
258-
{
259-
fs = closure->m->map_->query_point(idx,
260-
closure->x,
261-
closure->y);
262-
}
263-
else
264-
{
265-
fs = closure->m->map_->query_map_point(idx,
266-
closure->x,
267-
closure->y);
268-
}
269-
closure->featuresets.insert(std::make_pair(lyr.name(),fs));
270-
++idx;
271-
}
272-
}
273-
}
274-
catch (std::exception const& ex)
275-
{
276-
closure->error = true;
277-
closure->error_name = ex.what();
278-
}
279-
}
280-
281-
void Map::EIO_AfterQueryMap(uv_work_t* req)
282-
{
283-
Napi::HandleScope scope(env);
284-
Napi::AsyncResource async_resource(__func__);
285-
query_map_baton_t *closure = static_cast<query_map_baton_t *>(req->data);
286-
if (closure->error) {
287-
Napi::Value argv[1] = { Napi::Error::New(env, closure->error_name.c_str()) };
288-
async_resource.runInAsyncScope(Napi::GetCurrentContext()->Global(), Napi::New(env, closure->cb), 1, argv);
289-
} else {
290-
std::size_t num_result = closure->featuresets.size();
291-
if (num_result >= 1)
292-
{
293-
Napi::Array a = Napi::Array::New(env, num_result);
294-
typedef std::map<std::string,mapnik::featureset_ptr> fs_itr;
295-
fs_itr::const_iterator it = closure->featuresets.begin();
296-
fs_itr::const_iterator end = closure->featuresets.end();
297-
unsigned idx = 0;
298-
for (; it != end; ++it)
299-
{
300-
Napi::Object obj = Napi::Object::New(env);
301-
(obj).Set(Napi::String::New(env, "layer"), Napi::String::New(env, it->first));
302-
(obj).Set(Napi::String::New(env, "featureset"), Featureset::NewInstance(it->second));
303-
(a).Set(idx, obj);
304-
++idx;
305-
}
306-
closure->featuresets.clear();
307-
Napi::Value argv[2] = { env.Null(), a };
308-
async_resource.runInAsyncScope(Napi::GetCurrentContext()->Global(), Napi::New(env, closure->cb), 2, argv);
309-
}
310-
else
311-
{
312-
Napi::Value argv[2] = { env.Null(), env.Undefined() };
313-
async_resource.runInAsyncScope(Napi::GetCurrentContext()->Global(), Napi::New(env, closure->cb), 2, argv);
314-
}
315-
}
316-
317-
closure->m->Unref();
318-
closure->cb.Reset();
319-
delete closure;
320-
}
321-
*/

0 commit comments

Comments
 (0)