1
1
#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
+ }
2
99
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
- */
17
100
18
101
/* *
19
102
* Query a `Mapnik#Map` object to retrieve layer and feature data based on an
@@ -48,8 +131,7 @@ typedef struct {
48
131
49
132
Napi::Value Map::queryMapPoint (Napi::CallbackInfo const & info)
50
133
{
51
- // abstractQueryPoint(info,false);
52
- return info.Env ().Undefined ();
134
+ return query_point_impl (info,false );
53
135
}
54
136
55
137
/* *
@@ -85,25 +167,25 @@ Napi::Value Map::queryMapPoint(Napi::CallbackInfo const& info)
85
167
86
168
Napi::Value Map::queryPoint (Napi::CallbackInfo const & info)
87
169
{
88
- // abstractQueryPoint(info,true);
89
- return info.Env ().Undefined ();
170
+ return query_point_impl (info, true );
90
171
}
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)
93
174
{
175
+ Napi::Env env = info.Env ();
94
176
Napi::HandleScope scope (env);
95
177
if (info.Length () < 3 )
96
178
{
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 ();
99
181
return env.Undefined ();
100
182
}
101
183
102
- double x,y;
184
+ double x;
185
+ double y;
103
186
if (!info[0 ].IsNumber () || !info[1 ].IsNumber ())
104
187
{
105
188
Napi::TypeError::New (env, " x,y arguments must be numbers" ).ThrowAsJavaScriptException ();
106
-
107
189
return env.Undefined ();
108
190
}
109
191
else
@@ -112,36 +194,34 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
112
194
y = info[1 ].As <Napi::Number>().DoubleValue ();
113
195
}
114
196
115
- Map* m = info.Holder().Unwrap<Map>();
116
-
117
197
Napi::Object options = Napi::Object::New (env);
118
198
int layer_idx = -1 ;
119
199
120
200
if (info.Length () > 3 )
121
201
{
122
202
// options object
123
- if (!info[2].IsObject()) {
203
+ if (!info[2 ].IsObject ())
204
+ {
124
205
Napi::TypeError::New (env, " optional third argument must be an options object" ).ThrowAsJavaScriptException ();
125
-
126
206
return env.Undefined ();
127
207
}
128
208
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" ))
132
211
{
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
+ {
136
216
Napi::TypeError::New (env, " 'layer' option required for map query and must be either a layer name(string) or layer index (integer)" ).ThrowAsJavaScriptException ();
137
-
138
217
return env.Undefined ();
139
218
}
140
219
141
- if (layer_id.IsString()) {
220
+ if (layer_id.IsString ())
221
+ {
142
222
bool found = false ;
143
223
unsigned int idx (0 );
144
- std::string layer_name = TOSTR( layer_id);
224
+ std::string layer_name = layer_id. As <Napi::String>( );
145
225
for (mapnik::layer const & lyr : layers)
146
226
{
147
227
if (lyr.name () == layer_name)
@@ -157,7 +237,6 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
157
237
std::ostringstream s;
158
238
s << " Layer name '" << layer_name << " ' not found" ;
159
239
Napi::TypeError::New (env, s.str ().c_str ()).ThrowAsJavaScriptException ();
160
-
161
240
return env.Undefined ();
162
241
}
163
242
}
@@ -178,10 +257,11 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
178
257
{
179
258
s << " no layers found in map" ;
180
259
}
181
- Napi::TypeError::New(env, s.str().c_str()).ThrowAsJavaScriptException();
182
-
260
+ Napi::TypeError::New (env, s.str ()).ThrowAsJavaScriptException ();
183
261
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
+ {
185
265
std::ostringstream s;
186
266
s << " Zero-based layer index '" << layer_idx << " ' not valid, " ;
187
267
if (layer_num > 0 )
@@ -192,130 +272,20 @@ Napi::Value Map::abstractQueryPoint(Napi::CallbackInfo const& info, bool geo_coo
192
272
{
193
273
s << " no layers found in map" ;
194
274
}
195
- Napi::TypeError::New(env, s.str().c_str()).ThrowAsJavaScriptException();
196
-
275
+ Napi::TypeError::New (env, s.str ()).ThrowAsJavaScriptException ();
197
276
return env.Undefined ();
198
277
}
199
278
}
200
279
}
201
280
}
202
-
203
281
// ensure function callback
204
282
Napi::Value callback = info[info.Length () - 1 ];
205
- if (!callback->IsFunction()) {
283
+ if (!callback.IsFunction ())
284
+ {
206
285
Napi::TypeError::New (env, " last argument must be a callback function" ).ThrowAsJavaScriptException ();
207
-
208
286
return env.Undefined ();
209
287
}
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 ();
222
290
return env.Undefined ();
223
291
}
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