Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 39 additions & 13 deletions src/vtquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,41 +252,67 @@ struct Worker : Nan::AsyncWorker {
// implement closest point algorithm on query geometry and the query point
auto const cp_info = mapbox::geometry::algorithms::closest_point(query_geometry, query_point);

// convert x/y into lng/lat point
auto feature_lnglat = utils::convert_vt_to_ll(extent, tile_obj.z, tile_obj.x, tile_obj.y, cp_info);
auto meters = utils::distance_in_meters(query_lnglat, feature_lnglat);
// if radius is zero, and the distnace is zero, we have a point inside a polygon
// closest_point algorithm sets 0.0 if a boost::geometry::within test returns true
if (data.radius == 0.0 && cp_info.distance == 0.0) {
mapbox::geometry::point<double> original_coords{data.latitude, data.longitude};

// if the distance is within the threshold, save it
if (meters <= data.radius + 1) { // TODO(sam) https://github.com/mapbox/vtquery/issues/36

// decode properties (will be libvectortile eventually)
ResultObject::properties_type properties_list;
while (auto prop = feature.next_property()) {
std::string key = std::string{prop.key()};
vtzero::property_value_view value = prop.value();
properties_list.emplace_back(std::pair<std::string, vtzero::property_value_view>(key, value));
}

// emplace_back allows us to put a new object directly into the vector
// wherease push_back we need to create a new object in memory and move it into the vector
results_.emplace_back(std::move(properties_list),
layer_name,
std::move(feature_lnglat),
meters,
std::move(original_coords),
0.0,
original_geometry_type);

// otherwise let's check if the distance from the query point is within our desired radius
} else {
// convert x/y into lng/lat point
auto feature_lnglat = utils::convert_vt_to_ll(extent, tile_obj.z, tile_obj.x, tile_obj.y, cp_info);
auto meters = utils::distance_in_meters(query_lnglat, feature_lnglat);

// if the distance is within the threshold, save it
if (meters <= data.radius) { // TODO(sam) https://github.com/mapbox/vtquery/issues/36

// decode properties (will be libvectortile eventually)
ResultObject::properties_type properties_list;
while (auto prop = feature.next_property()) {
std::string key = std::string{prop.key()};
vtzero::property_value_view value = prop.value();
properties_list.emplace_back(std::pair<std::string, vtzero::property_value_view>(key, value));
}

// emplace_back allows us to put a new object directly into the vector
// wherease push_back we need to create a new object in memory and move it into the vector
results_.emplace_back(std::move(properties_list),
layer_name,
std::move(feature_lnglat),
meters,
original_geometry_type);
}
}


} // end tile.layer.feature loop
} // end tile.layer loop
} // end tile loop

// create sort vector

sorted_results_.reserve(results_.size());
for (auto& r : results_) {
sorted_results_.push_back(&r); // save the pointer of r
}

// sort based on distance
std::sort(sorted_results_.begin(), sorted_results_.end(), [](ResultObject const* a, ResultObject const* b) { return a->distance < b->distance; });
// sort based on distance (unless radius is zero, in which case there is no need to sort)
if (data.radius > 0.0) {
std::sort(sorted_results_.begin(), sorted_results_.end(), [](ResultObject const* a, ResultObject const* b) { return a->distance < b->distance; });
}

} catch (const std::exception& e) {
SetErrorMessage(e.what());
Expand Down
23 changes: 17 additions & 6 deletions test/vtquery.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ test('options - defaults: success', assert => {

test('options - radius: all results within radius', assert => {
const buffer = bufferSF;
const ll = [-122.4477, 37.7665]; // direct hit
const ll = [-122.4477, 37.7665];
vtquery([{buffer: buffer, z: 15, x: 5238, y: 12666}], ll, { numResults: 100, radius: 1000 }, function(err, result) {
assert.ifError(err);
result.features.forEach(function(feature) {
Expand All @@ -424,9 +424,20 @@ test('options - radius: all results within radius', assert => {
});
});

test('options - radius=0: only returns "point in polygon" results (on a building)', assert => {
const buffer = bufferSF;
const ll = [-122.4527, 37.7689]; // direct hit on a building
vtquery([{buffer: buffer, z: 15, x: 5238, y: 12666}], ll, { radius: 0, layers: ['building'] }, function(err, result) {
assert.ifError(err);
assert.equal(result.features.length, 1, 'only one building returned');
assert.deepEqual(result.features[0].properties.tilequery, { distance: 0.0, layer: 'building', geometry: 'polygon' }, 'expected tilequery info');
assert.end();
});
});

test('options - numResults: successfully limits results', assert => {
const buffer = bufferSF;
const ll = [-122.4477, 37.7665]; // direct hit
const ll = [-122.4477, 37.7665];
vtquery([{buffer: buffer, z: 15, x: 5238, y: 12666}], ll, { numResults: 1, radius: 1000 }, function(err, result) {
assert.ifError(err);
assert.equal(result.features.length, 1, 'expected length');
Expand All @@ -436,7 +447,7 @@ test('options - numResults: successfully limits results', assert => {

test('options - layers: successfully returns only requested layers', assert => {
const buffer = bufferSF;
const ll = [-122.4477, 37.7665]; // direct hit
const ll = [-122.4477, 37.7665];
vtquery([{buffer: buffer, z: 15, x: 5238, y: 12666}], ll, {radius: 2000, layers: ['poi_label']}, function(err, result) {
assert.ifError(err);
result.features.forEach(function(feature) {
Expand All @@ -448,7 +459,7 @@ test('options - layers: successfully returns only requested layers', assert => {

test('options - geometry: successfully returns only points', assert => {
const buffer = bufferSF;
const ll = [-122.4477, 37.7665]; // direct hit
const ll = [-122.4477, 37.7665];
vtquery([{buffer: buffer, z: 15, x: 5238, y: 12666}], ll, {radius: 2000, geometry: 'point'}, function(err, result) {
assert.ifError(err);
assert.equal(result.features.length, 5, 'expected number of features');
Expand All @@ -461,7 +472,7 @@ test('options - geometry: successfully returns only points', assert => {

test('options - geometry: successfully returns only linestrings', assert => {
const buffer = bufferSF;
const ll = [-122.4477, 37.7665]; // direct hit
const ll = [-122.4477, 37.7665];
vtquery([{buffer: buffer, z: 15, x: 5238, y: 12666}], ll, {radius: 200, geometry: 'linestring'}, function(err, result) {
assert.ifError(err);
assert.equal(result.features.length, 5, 'expected number of features');
Expand All @@ -475,7 +486,7 @@ test('options - geometry: successfully returns only linestrings', assert => {

test('options - geometry: successfully returns only polygons', assert => {
const buffer = bufferSF;
const ll = [-122.4477, 37.7665]; // direct hit
const ll = [-122.4477, 37.7665];
vtquery([{buffer: buffer, z: 15, x: 5238, y: 12666}], ll, {radius: 200, geometry: 'polygon'}, function(err, result) {
assert.ifError(err);
assert.equal(result.features.length, 5, 'expected number of features');
Expand Down