Remove polygon copying overhead
This commit is contained in:
parent
421115200b
commit
20ff138f08
@ -20,7 +20,7 @@ struct LocationDependentData
|
|||||||
{
|
{
|
||||||
using point_t = boost::geometry::model::d2::
|
using point_t = boost::geometry::model::d2::
|
||||||
point_xy<double, boost::geometry::cs::spherical_equatorial<boost::geometry::degree>>;
|
point_xy<double, boost::geometry::cs::spherical_equatorial<boost::geometry::degree>>;
|
||||||
using segment_t = std::pair<point_t, point_t>;
|
using segment_t = boost::geometry::model::segment<point_t>;
|
||||||
using polygon_t = boost::geometry::model::polygon<point_t>;
|
using polygon_t = boost::geometry::model::polygon<point_t>;
|
||||||
using polygon_bands_t = std::vector<std::vector<segment_t>>;
|
using polygon_bands_t = std::vector<std::vector<segment_t>>;
|
||||||
using box_t = boost::geometry::model::box<point_t>;
|
using box_t = boost::geometry::model::box<point_t>;
|
||||||
|
@ -87,56 +87,42 @@ void LocationDependentData::loadLocationDependentData(const boost::filesystem::p
|
|||||||
return index;
|
return index;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto convert_to_ring = [](const auto &coordinates_array) -> polygon_t::ring_type {
|
auto index_polygon = [this, &bounding_boxes](const auto &rings, auto properties_index) {
|
||||||
polygon_t::ring_type ring;
|
// At least an outer ring in polygon https://tools.ietf.org/html/rfc7946#section-3.1.6
|
||||||
for (rapidjson::SizeType i = 0; i < coordinates_array.Size(); ++i)
|
|
||||||
{
|
|
||||||
util::validateCoordinate(coordinates_array[i]);
|
|
||||||
const auto &coords = coordinates_array[i].GetArray();
|
|
||||||
ring.emplace_back(coords[0].GetDouble(), coords[1].GetDouble());
|
|
||||||
}
|
|
||||||
return ring;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto index_polygon = [this, &bounding_boxes, &convert_to_ring](const auto &rings,
|
|
||||||
auto properties_index) {
|
|
||||||
// https://tools.ietf.org/html/rfc7946#section-3.1.6
|
|
||||||
BOOST_ASSERT(rings.Size() > 0);
|
BOOST_ASSERT(rings.Size() > 0);
|
||||||
polygon_t polygon;
|
|
||||||
polygon.outer() = convert_to_ring(rings[0].GetArray());
|
|
||||||
for (rapidjson::SizeType iring = 1; iring < rings.Size(); ++iring)
|
|
||||||
{
|
|
||||||
polygon.inners().emplace_back(convert_to_ring(rings[iring].GetArray()));
|
|
||||||
}
|
|
||||||
auto envelop = boost::geometry::return_envelope<box_t>(polygon);
|
|
||||||
bounding_boxes.emplace_back(envelop, polygons.size());
|
|
||||||
|
|
||||||
// here is a part of ExtractPolygon::ExtractPolygon code
|
auto to_point = [](const auto &json) -> point_t {
|
||||||
// TODO: remove copy overhead
|
util::validateCoordinate(json);
|
||||||
constexpr const int32_t segments_per_band = 10;
|
const auto &coords = json.GetArray();
|
||||||
constexpr const int32_t max_bands = 10000;
|
return {coords[0].GetDouble(), coords[1].GetDouble()};
|
||||||
const auto y_min = envelop.min_corner().y();
|
};
|
||||||
const auto y_max = envelop.max_corner().y();
|
|
||||||
|
|
||||||
std::vector<segment_t> segments;
|
std::vector<segment_t> segments;
|
||||||
auto add_ring = [&segments](const auto &ring) {
|
auto append_ring_segments = [&segments, &to_point](const auto &coordinates_array) -> box_t {
|
||||||
auto it = ring.begin();
|
box_t envelop;
|
||||||
const auto end = ring.end();
|
if (!coordinates_array.Empty())
|
||||||
|
|
||||||
BOOST_ASSERT(it != end);
|
|
||||||
auto last_it = it++;
|
|
||||||
while (it != end)
|
|
||||||
{
|
{
|
||||||
segments.emplace_back(*last_it, *it);
|
point_t curr = to_point(coordinates_array[0]), next;
|
||||||
last_it = it++;
|
for (rapidjson::SizeType i = 1; i < coordinates_array.Size(); ++i, curr = next)
|
||||||
|
{
|
||||||
|
next = to_point(coordinates_array[i]);
|
||||||
|
segments.emplace_back(curr, next);
|
||||||
|
boost::geometry::expand(envelop, next);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return envelop;
|
||||||
};
|
};
|
||||||
|
|
||||||
add_ring(polygon.outer());
|
auto envelop = append_ring_segments(rings[0].GetArray());
|
||||||
for (const auto &ring : polygon.inners())
|
bounding_boxes.emplace_back(envelop, polygons.size());
|
||||||
add_ring(ring);
|
for (rapidjson::SizeType iring = 1; iring < rings.Size(); ++iring)
|
||||||
|
{
|
||||||
|
append_ring_segments(rings[iring].GetArray());
|
||||||
|
}
|
||||||
|
|
||||||
int32_t num_bands = static_cast<int32_t>(segments.size()) / segments_per_band;
|
constexpr const std::size_t segments_per_band = 10;
|
||||||
|
constexpr const std::size_t max_bands = 10000;
|
||||||
|
auto num_bands = segments.size() / segments_per_band;
|
||||||
if (num_bands < 1)
|
if (num_bands < 1)
|
||||||
{
|
{
|
||||||
num_bands = 1;
|
num_bands = 1;
|
||||||
@ -147,6 +133,9 @@ void LocationDependentData::loadLocationDependentData(const boost::filesystem::p
|
|||||||
}
|
}
|
||||||
|
|
||||||
polygon_bands_t bands(num_bands);
|
polygon_bands_t bands(num_bands);
|
||||||
|
|
||||||
|
const auto y_min = envelop.min_corner().y();
|
||||||
|
const auto y_max = envelop.max_corner().y();
|
||||||
const auto dy = (y_max - y_min) / num_bands;
|
const auto dy = (y_max - y_min) / num_bands;
|
||||||
|
|
||||||
for (const auto &segment : segments)
|
for (const auto &segment : segments)
|
||||||
@ -155,15 +144,13 @@ void LocationDependentData::loadLocationDependentData(const boost::filesystem::p
|
|||||||
const std::pair<coord_t, coord_t> mm =
|
const std::pair<coord_t, coord_t> mm =
|
||||||
std::minmax(segment.first.y(), segment.second.y());
|
std::minmax(segment.first.y(), segment.second.y());
|
||||||
const auto band_min = std::min<coord_t>(num_bands - 1, (mm.first - y_min) / dy);
|
const auto band_min = std::min<coord_t>(num_bands - 1, (mm.first - y_min) / dy);
|
||||||
const auto band_max = std::min<coord_t>(
|
const auto band_max = std::min<coord_t>(num_bands, ((mm.second - y_min) / dy) + 1);
|
||||||
num_bands, ((mm.second - y_min) / dy) + 1); // TODO: use integer coordinates
|
|
||||||
|
|
||||||
for (auto band = band_min; band < band_max; ++band)
|
for (auto band = band_min; band < band_max; ++band)
|
||||||
{
|
{
|
||||||
bands[band].push_back(segment);
|
bands[band].push_back(segment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// EOC
|
|
||||||
|
|
||||||
polygons.emplace_back(std::make_pair(bands, properties_index));
|
polygons.emplace_back(std::make_pair(bands, properties_index));
|
||||||
};
|
};
|
||||||
@ -221,7 +208,7 @@ LocationDependentData::properties_t LocationDependentData::operator()(const poin
|
|||||||
|
|
||||||
const auto y_min = envelop.min_corner().y();
|
const auto y_min = envelop.min_corner().y();
|
||||||
const auto y_max = envelop.max_corner().y();
|
const auto y_max = envelop.max_corner().y();
|
||||||
auto dy = (y_max - y_min) / bands.size();
|
const auto dy = (y_max - y_min) / bands.size();
|
||||||
|
|
||||||
std::size_t band = (point.y() - y_min) / dy;
|
std::size_t band = (point.y() - y_min) / dy;
|
||||||
if (band >= bands.size())
|
if (band >= bands.size())
|
||||||
@ -277,6 +264,9 @@ LocationDependentData::properties_t LocationDependentData::operator()(const osmi
|
|||||||
// For more complicated scenarios a proper merging of multiple tags
|
// For more complicated scenarios a proper merging of multiple tags
|
||||||
// at one or many locations must be provided
|
// at one or many locations must be provided
|
||||||
const auto &nodes = way.nodes();
|
const auto &nodes = way.nodes();
|
||||||
|
|
||||||
|
// TODO: the next call requires an OSM file preprocessed with a command
|
||||||
|
// osmium add-locations-to-ways --keep-untagged-nodes
|
||||||
const auto &location = nodes.back().location();
|
const auto &location = nodes.back().location();
|
||||||
const point_t point(location.lon(), location.lat());
|
const point_t point(location.lon(), location.lat());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user