Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Header-only polygon_bounding_boxes and linestring_bounding_boxes, make_geometry_id_iterator utility, and box<T> class. #820

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a23f06a
Add failing tests and empty header-only implementation
harrism Nov 23, 2022
dcc0f7f
Working header-only API
harrism Nov 23, 2022
df8d8f9
Port column-based API to call header-only API
harrism Nov 23, 2022
fe7bf68
Merge branch 'branch-23.02' into fea-header-only-polygon-bboxes
harrism Nov 24, 2022
44e2bd2
Fix tests, add expansion_radius
harrism Nov 24, 2022
5b87d80
Reinstate early out for empty
harrism Nov 24, 2022
02ad17b
tests
harrism Nov 24, 2022
2675fef
Add make_box_output_iterator and make_geometry_id_iterator factories.
harrism Nov 30, 2022
947da30
box type
harrism Nov 30, 2022
18642c1
use make_geometry_id_iterator
harrism Nov 30, 2022
2fdd802
Use box type
harrism Nov 30, 2022
bec3e95
doc
harrism Nov 30, 2022
7f85e72
Correct tparam name in doc
harrism Nov 30, 2022
1ebaea8
implementation tparam names
harrism Nov 30, 2022
a9bf663
header-only linestring_bounding_boxes refactor
harrism Nov 30, 2022
2df0fae
Merge branch 'branch-23.02' into fea-header-only-polygon-bboxes
harrism Dec 6, 2022
6f5bf15
Add deduction guides.
harrism Dec 7, 2022
de41f67
Fix index_to_geometry_id to actually return an ID and fix examples in…
harrism Dec 7, 2022
26acde0
Merge branch 'branch-23.02' into fea-header-only-polygon-bboxes
harrism Dec 13, 2022
63f770b
Merge branch 'branch-23.02' into fea-header-only-polygon-bboxes
harrism Dec 13, 2022
4b27c39
Generalize expect_segment_equivalent to expect_vec_2d_pair_equivalent…
harrism Dec 13, 2022
c86a332
Document segment and make more generic.
harrism Dec 13, 2022
79a9168
doc
harrism Dec 13, 2022
e0fc84a
doc
harrism Dec 13, 2022
fb1f2be
Missed first->v1, second -> v2
harrism Dec 13, 2022
fc2b339
Comply with GeoArrow spec for geometry and part offsets.
harrism Dec 13, 2022
fd8a67e
Add column API doc precondition about offsets for GeoArrow
harrism Dec 13, 2022
586e471
Fix python tests and column-based API offset size expectations
harrism Dec 14, 2022
53d3e0e
As above for linestring
harrism Dec 14, 2022
bce13d3
Add insufficient offsets test
harrism Dec 14, 2022
69ea0a1
include
harrism Dec 14, 2022
d0f7541
Add missing param docs
harrism Dec 14, 2022
434bf2f
Merge branch 'branch-23.02' into fea-header-only-polygon-bboxes
harrism Dec 14, 2022
b22019a
Fix quadtree bounding box tests for arrow offsets
harrism Dec 14, 2022
54f3bb0
Fix spatial join pytest
harrism Dec 14, 2022
d630cbb
Merge branch 'branch-23.02' into fea-header-only-polygon-bboxes
harrism Dec 14, 2022
7e1576a
Fix segment conflicts
harrism Dec 14, 2022
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
137 changes: 137 additions & 0 deletions cpp/include/cuspatial/experimental/detail/polygon_bounding_boxes.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <cuspatial/experimental/bounding_box.cuh>
#include <cuspatial/traits.hpp>

#include <rmm/cuda_stream_view.hpp>
#include <rmm/device_vector.hpp>
#include <rmm/exec_policy.hpp>

#include <thrust/gather.h>
#include <thrust/scan.h>
#include <thrust/scatter.h>

namespace cuspatial {

thomcom marked this conversation as resolved.
Show resolved Hide resolved
namespace detail {

template <class T,
class OffsetIteratorA,
class OffsetIteratorB,
class VertexIterator,
class BoundingBoxIterator>
BoundingBoxIterator polygon_bounding_boxes(OffsetIteratorA polygon_offsets_first,
OffsetIteratorA polygon_offsets_last,
OffsetIteratorB polygon_ring_offsets_first,
OffsetIteratorB polygon_ring_offsets_last,
VertexIterator polygon_vertices_first,
VertexIterator polygon_vertices_last,
BoundingBoxIterator bounding_boxes_first,
T expansion_radius,
rmm::cuda_stream_view stream)
{
auto const num_polygons = std::distance(polygon_offsets_first, polygon_offsets_last);
auto const num_rings = std::distance(polygon_ring_offsets_first, polygon_ring_offsets_last);
auto const num_poly_vertices = std::distance(polygon_vertices_first, polygon_vertices_last);

// Wrapped in an IIFE so `first_ring_offsets` is freed on return
auto vertex_ids = [&]() {
// TODO: use device_uvector
rmm::device_vector<int32_t> vertex_ids(num_poly_vertices);
rmm::device_vector<int32_t> first_ring_offsets(num_polygons);

// Gather the first ring offset for each polygon
thrust::gather(rmm::exec_policy(stream),
polygon_offsets_first,
polygon_offsets_last,
polygon_ring_offsets_first,
first_ring_offsets.begin());

// Scatter the first ring offset into a list of vertex_ids for reduction
thrust::scatter(rmm::exec_policy(stream),
thrust::make_counting_iterator(0),
thrust::make_counting_iterator(0) + num_polygons,
first_ring_offsets.begin(),
vertex_ids.begin());

thrust::inclusive_scan(rmm::exec_policy(stream),
vertex_ids.begin(),
vertex_ids.end(),
vertex_ids.begin(),
thrust::maximum<int32_t>());

return vertex_ids;
}();
harrism marked this conversation as resolved.
Show resolved Hide resolved

return point_bounding_boxes(vertex_ids.begin(),
vertex_ids.end(),
polygon_vertices_first,
bounding_boxes_first,
expansion_radius,
stream);
}

} // namespace detail

template <class OffsetIteratorA,
class OffsetIteratorB,
class VertexIterator,
class BoundingBoxIterator,
class T>
BoundingBoxIterator polygon_bounding_boxes(OffsetIteratorA polygon_offsets_first,
OffsetIteratorA polygon_offsets_last,
OffsetIteratorB polygon_ring_offsets_first,
OffsetIteratorB polygon_ring_offsets_last,
VertexIterator polygon_vertices_first,
VertexIterator polygon_vertices_last,
BoundingBoxIterator bounding_boxes_first,
T expansion_radius,
rmm::cuda_stream_view stream)
{
static_assert(is_floating_point<T>(), "Only floating point polygon vertices supported");

static_assert(is_same<vec_2d<T>, iterator_value_type<VertexIterator>>(),
"Input vertices must be cuspatial::vec_2d");

static_assert(cuspatial::is_integral<iterator_value_type<OffsetIteratorA>,
iterator_value_type<OffsetIteratorB>>(),
"OffsetIterators must have integral value type.");

auto const num_polys = std::distance(polygon_offsets_first, polygon_offsets_last);
auto const num_rings = std::distance(polygon_ring_offsets_first, polygon_ring_offsets_last);
auto const num_poly_vertices = std::distance(polygon_vertices_first, polygon_vertices_last);

CUSPATIAL_EXPECTS(num_rings >= num_polys, "Each polygon must have at least one ring");

CUSPATIAL_EXPECTS(num_poly_vertices >= num_polys * 3,
"Each ring must have at least three vertices");

if (num_polys == 0 || num_rings == 0 || num_poly_vertices == 0) { return bounding_boxes_first; }

return detail::polygon_bounding_boxes<T>(polygon_offsets_first,
polygon_offsets_last,
polygon_ring_offsets_first,
polygon_ring_offsets_last,
polygon_vertices_first,
polygon_vertices_last,
bounding_boxes_first,
expansion_radius,
stream);
}
} // namespace cuspatial
42 changes: 42 additions & 0 deletions cpp/include/cuspatial/experimental/polygon_bounding_boxes.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <cuspatial/traits.hpp>

#include <rmm/cuda_stream_view.hpp>

namespace cuspatial {

template <class OffsetIteratorA,
class OffsetIteratorB,
class VertexIterator,
class BoundingBoxIterator,
class T = iterator_vec_base_type<VertexIterator>>
BoundingBoxIterator polygon_bounding_boxes(OffsetIteratorA polygon_offsets_first,
harrism marked this conversation as resolved.
Show resolved Hide resolved
OffsetIteratorA polygon_offsets_last,
OffsetIteratorB polygon_ring_offsets_first,
OffsetIteratorB polygon_ring_offsets_last,
VertexIterator polygon_vertices_first,
VertexIterator polygon_vertices_last,
BoundingBoxIterator bounding_boxes_first,
T expansion_radius = T{0},
rmm::cuda_stream_view stream = rmm::cuda_stream_default);

} // namespace cuspatial

#include <cuspatial/experimental/detail/polygon_bounding_boxes.cuh>
69 changes: 12 additions & 57 deletions cpp/src/spatial/polygon_bounding_box.cu
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
*/

#include <cuspatial/error.hpp>
#include <cuspatial/experimental/bounding_box.cuh>

#include <cuspatial/experimental/iterator_factory.cuh>
#include <cuspatial/experimental/polygon_bounding_boxes.cuh>

#include <cudf/column/column_factories.hpp>
#include <cudf/column/column_view.hpp>
Expand All @@ -28,36 +29,14 @@
#include <rmm/cuda_stream_view.hpp>
#include <rmm/exec_policy.hpp>

#include <thrust/functional.h>
#include <thrust/gather.h>
#include <thrust/iterator/constant_iterator.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/reduce.h>
#include <thrust/scan.h>
#include <thrust/scatter.h>
#include <thrust/tuple.h>

#include <memory>
#include <vector>

namespace cuspatial {

namespace {

template <typename T>
struct point_to_square {
inline __device__ thrust::tuple<T, T, T, T> operator()(thrust::tuple<T, T> const& point)
{
return thrust::make_tuple(thrust::get<0>(point), // x
thrust::get<1>(point), // y
thrust::get<0>(point), // x
thrust::get<1>(point)); // y
}
};

template <typename T>
std::unique_ptr<cudf::table> compute_polygon_bounding_boxes(cudf::column_view const& poly_offsets,
cudf::column_view const& ring_offsets,
Expand All @@ -68,33 +47,6 @@ std::unique_ptr<cudf::table> compute_polygon_bounding_boxes(cudf::column_view co
rmm::mr::device_memory_resource* mr)
{
auto num_polygons = poly_offsets.size();
// Wrapped in an IEFE so `first_ring_offsets` is freed on return
auto point_ids = [&]() {
rmm::device_vector<int32_t> point_ids(x.size());
rmm::device_vector<int32_t> first_ring_offsets(num_polygons);

// Gather the first ring offset for each polygon
thrust::gather(rmm::exec_policy(stream),
poly_offsets.begin<int32_t>(),
poly_offsets.end<int32_t>(),
ring_offsets.begin<int32_t>(),
first_ring_offsets.begin());

// Scatter the first ring offset into a list of point_ids for reduction
thrust::scatter(rmm::exec_policy(stream),
thrust::make_counting_iterator(0),
thrust::make_counting_iterator(0) + num_polygons,
first_ring_offsets.begin(),
point_ids.begin());

thrust::inclusive_scan(rmm::exec_policy(stream),
point_ids.begin(),
point_ids.end(),
point_ids.begin(),
thrust::maximum<int32_t>());

return point_ids;
}();

auto type = cudf::data_type{cudf::type_to_id<T>()};
std::vector<std::unique_ptr<cudf::column>> cols{};
Expand All @@ -108,19 +60,22 @@ std::unique_ptr<cudf::table> compute_polygon_bounding_boxes(cudf::column_view co
cols.push_back(
cudf::make_numeric_column(type, num_polygons, cudf::mask_state::UNALLOCATED, stream, mr));

auto points_begin = cuspatial::make_vec_2d_iterator(x.begin<T>(), y.begin<T>());
auto vertices_begin = cuspatial::make_vec_2d_iterator(x.begin<T>(), y.begin<T>());

auto bbox_mins = cuspatial::make_vec_2d_output_iterator(cols.at(0)->mutable_view().begin<T>(),
cols.at(1)->mutable_view().begin<T>());
auto bbox_maxes = cuspatial::make_vec_2d_output_iterator(cols.at(2)->mutable_view().begin<T>(),
cols.at(3)->mutable_view().begin<T>());

point_bounding_boxes(point_ids.begin(),
point_ids.end(),
points_begin,
thrust::make_zip_iterator(bbox_mins, bbox_maxes),
expansion_radius,
stream);
cuspatial::polygon_bounding_boxes(poly_offsets.begin<cudf::size_type>(),
poly_offsets.end<cudf::size_type>(),
ring_offsets.begin<cudf::size_type>(),
ring_offsets.end<cudf::size_type>(),
vertices_begin,
vertices_begin + x.size(),
thrust::make_zip_iterator(bbox_mins, bbox_maxes),
expansion_radius,
stream);

return std::make_unique<cudf::table>(std::move(cols));
}
Expand Down
8 changes: 6 additions & 2 deletions cpp/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ ConfigureTest(POINT_QUADTREE_TEST
ConfigureTest(LINESTRING_BBOX_TEST
spatial/linestring_bbox_test.cu)

ConfigureTest(POLYGON_BBOX_TEST
spatial/polygon_bbox_test.cu)
ConfigureTest(POLYGON_BOUNDING_BOXES_TEST
spatial/polygon_bounding_boxes_test.cu)

ConfigureTest(POINT_DISTANCE_TEST
spatial/point_distance_test.cpp)
Expand Down Expand Up @@ -118,6 +118,10 @@ ConfigureTest(UTILITY_TEST
# Experimental API
ConfigureTest(HAVERSINE_TEST_EXP
experimental/spatial/haversine_test.cu)

ConfigureTest(POLYGON_BOUNDING_BOXES_TEST_EXP
experimental/spatial/polygon_bounding_boxes_test.cu)

ConfigureTest(POINT_DISTANCE_TEST_EXP
experimental/spatial/point_distance_test.cu)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* limitations under the License.
*/

#include <cuspatial_test/base_fixture.hpp>
#include <cuspatial_test/vector_equality.hpp>
#include <cuspatial_test/vector_factories.cuh>
#include <tests/base_fixture.hpp>

#include <rmm/cuda_stream_view.hpp>
#include <rmm/device_vector.hpp>
Expand Down
2 changes: 1 addition & 1 deletion cpp/tests/experimental/operators/linestrings_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
* limitations under the License.
*/

#include <cuspatial_test/base_fixture.hpp>
#include <cuspatial_test/vector_equality.hpp>
#include <tests/base_fixture.hpp>

#include <cuspatial/cuda_utils.hpp>
#include <cuspatial/detail/utility/linestring.cuh>
Expand Down
Loading