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
49132Napi::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
86168Napi::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