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

Add column API for pairwise_point_polygon_distance #984

Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
965b80a
initial
isVoid Feb 28, 2023
38af8e6
Merge branch 'branch-23.04' of https://github.com/rapidsai/cuspatial …
isVoid Mar 1, 2023
02f61fe
add pragma once for floating_point.cuh
isVoid Mar 7, 2023
7bd797f
add polygon_ref structure
isVoid Mar 7, 2023
0968c15
add multipolygon_ref class
isVoid Mar 7, 2023
a659eab
update multipolygon_range class
isVoid Mar 7, 2023
c274070
update multipoint_range class
isVoid Mar 7, 2023
12ffa53
update is_point_in_polygon usage with polygon_ref
isVoid Mar 7, 2023
7490333
update multilinestring_range
isVoid Mar 7, 2023
f665287
add point to polygon kernel
isVoid Mar 7, 2023
291f6e6
add segment deduction guide
isVoid Mar 7, 2023
efa6883
add owning object type to vector factories
isVoid Mar 7, 2023
23146ef
add tests
isVoid Mar 7, 2023
ead160a
add helper files
isVoid Mar 7, 2023
09bd35f
add more tests
isVoid Mar 8, 2023
92760d1
bug fixes
isVoid Mar 8, 2023
8acb5dc
cleanups
isVoid Mar 8, 2023
a2b94fe
fix tests
isVoid Mar 8, 2023
46a67fe
optimize single point range input
isVoid Mar 8, 2023
b725b52
docs, type checks in range ctor
isVoid Mar 8, 2023
cb5706a
Merge branch 'branch-23.04' into feature/polygon_distances
isVoid Mar 8, 2023
ab59e7d
use range based for loop in is_point_in_polygon
isVoid Mar 8, 2023
ddcd5d2
initial column API
isVoid Mar 9, 2023
b136c0b
Apply suggestions from code review
isVoid Mar 9, 2023
744f32f
add docs
isVoid Mar 9, 2023
bb6c637
style
isVoid Mar 9, 2023
756650b
Merge branch 'branch-23.04' of https://github.com/rapidsai/cuspatial …
isVoid Mar 9, 2023
ec23d6e
add column API tests, augment column_factories
isVoid Mar 10, 2023
8319e7c
fix bug in PiP tests
isVoid Mar 10, 2023
85fab66
Merge branch 'feature/polygon_distances' into feature/point_polygon_d…
isVoid Mar 10, 2023
43cc02a
add validation checks
isVoid Mar 10, 2023
386ad1f
Merge branch 'branch-23.04' of https://github.com/rapidsai/cuspatial …
isVoid Mar 21, 2023
402a8e3
remove unused code pieces and files
isVoid Mar 21, 2023
67c931b
Merge branch 'branch-23.04' into feature/point_polygon_distance_colum…
isVoid Mar 21, 2023
3f1da02
address docs review
isVoid Mar 21, 2023
4b33176
Merge branch 'feature/point_polygon_distance_column_api' of github.co…
isVoid Mar 21, 2023
961f6ce
Merge branch 'branch-23.04' into feature/point_polygon_distance_colum…
isVoid Mar 21, 2023
50b6c6b
style
isVoid Mar 21, 2023
375fae1
Merge branch 'feature/point_polygon_distance_column_api' of github.co…
isVoid Mar 21, 2023
16379c2
address reviews
isVoid Mar 21, 2023
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
1 change: 1 addition & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ add_library(cuspatial
src/spatial/linestring_intersection.cu
src/spatial/point_distance.cu
src/spatial/point_linestring_distance.cu
src/spatial/point_polygon_distance.cu
src/spatial/point_linestring_nearest_points.cu
src/spatial/sinusoidal_projection.cu
src/trajectory/derive_trajectories.cu
Expand Down
28 changes: 28 additions & 0 deletions cpp/include/cuspatial/detail/utility/validation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,31 @@
"Each polygon must have at least one (1) ring"); \
CUSPATIAL_EXPECTS(num_poly_points >= 4 * (num_poly_ring_offsets - 1), \
"Each ring must have at least four (4) vertices");

/**
* @brief Macro for validating the data array sizes for a multipolygon.
*
* Raises an exception if any of the following are false:
* - The number of multipolygon offsets is greater than zero.
* - The number of polygon offsets is greater than zero.
* - The number of ring offsets is greater than zero.
* - There is at least one ring offset per polygon offset.
* - There are at least four vertices per ring offset.
*
* MultiPolygons follow [GeoArrow data layout][1]. Offsets arrays (polygons and rings) have one more
* element than the number of items in the array. The last offset is always the sum of the previous
* offset and the size of that element. For example the last value in the ring offsets array is the
* last ring offset plus the number of rings in the last polygon. See
* [Arrow Variable-Size Binary layout](2). Note that an empty list still has one offset: {0}.
*
* Rings are assumed to be closed (closed means the first and last vertices of
* each ring are equal). Therefore rings must have at least 4 vertices.
*
* [1]: https://github.com/geoarrow/geoarrow/blob/main/format.md
* [2]: https://arrow.apache.org/docs/format/Columnar.html#variable-size-binary-layout
*/
#define CUSPATIAL_EXPECTS_VALID_MULTIPOLYGON_SIZES( \
num_poly_points, num_multipoly_offsets, num_poly_offsets, num_poly_ring_offsets) \
CUSPATIAL_EXPECTS(num_multipoly_offsets > 0, \
"Multipolygon offsets must contain at least one (1) value"); \
CUSPATIAL_EXPECTS_VALID_POLYGON_SIZES(num_poly_points, num_poly_offsets, num_poly_ring_offsets);
49 changes: 49 additions & 0 deletions cpp/include/cuspatial/distance/point_polygon_distance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2023, 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/column/geometry_column_view.hpp>

#include <cudf/column/column_view.hpp>

#include <optional>

namespace cuspatial {

/**
* @ingroup distance
* @brief Compute pairwise (multi)point-to-(multi)polygon Cartesian distance
*
* @param multipoints Geometry column of multipoints
* @param multipolygons Geometry column of multipolygons
isVoid marked this conversation as resolved.
Show resolved Hide resolved
* @param mr Device memory resource used to allocate the returned column.
* @return Column of distances between each pair of input geometries, same type as input coordinate
* types.
*
* @throw cuspatial::logic_error if `multipoints` and `multipolygons` has different coordinate
* types.
* @throw cuspatial::logic_error if `multipoints` is not a point column and `multipolygons` is not a
* polygon column.
* @throw cuspatial::logic_error if input column sizes mismatch.
*/

std::unique_ptr<cudf::column> pairwise_point_polygon_distance(
geometry_column_view const& multipoints,
geometry_column_view const& multipolygons,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource());

} // namespace cuspatial
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ namespace detail {
* @return boolean to indicate if point is inside the polygon.
* `false` if point is on the edge of the polygon.
*
* @tparam T type of coordinate
* @tparam PolygonRef polygon_ref type
* @param test_point point to test for point in polygon
* @param polygon polygon to test for point in polygon
* @return boolean to indicate if point is inside the polygon.
* `false` if point is on the edge of the polygon.
*
* TODO: the ultimate goal of refactoring this as independent function is to remove
* src/utility/point_in_polygon.cuh and its usage in quadtree_point_in_polygon.cu. It isn't
* possible today without further work to refactor quadtree_point_in_polygon into header only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <cuspatial/cuda_utils.hpp>
#include <cuspatial/detail/iterator.hpp>
#include <cuspatial/detail/utility/validation.hpp>
#include <cuspatial/experimental/geometry/segment.cuh>
#include <cuspatial/experimental/geometry_collection/multipolygon_ref.cuh>
#include <cuspatial/traits.hpp>
Expand All @@ -32,7 +33,6 @@
#include <optional>

namespace cuspatial {

using namespace detail;

template <typename GeometryIterator,
Expand Down Expand Up @@ -104,7 +104,10 @@ multipolygon_range<GeometryIterator, PartIterator, RingIterator, VecIterator>::m
_point_end(point_end)
{
static_assert(is_vec_2d<iterator_value_type<VecIterator>>(),
"Coordinate range must be constructed with iterators to vec_2d.");
"Point iterator must be iterators to floating point vec_2d types.");

CUSPATIAL_EXPECTS_VALID_MULTIPOLYGON_SIZES(
num_points(), num_multipolygons() + 1, num_polygons() + 1, num_rings() + 1);
}

template <typename GeometryIterator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ auto make_multilinestring_range(GeometryColumnView const& linestrings_column)
"Must be Linestring geometry type.");
auto geometry_iter = thrust::make_counting_iterator(0);
auto const& part_offsets = linestrings_column.offsets();
auto const& points_xy = linestrings_column.child().child(1);
auto const& points_xy = linestrings_column.child().child(1); // Ignores x-y offset {0, 2, 4...}

auto points_it = make_vec_2d_iterator(points_xy.template begin<T>());

Expand Down Expand Up @@ -276,7 +276,7 @@ auto make_multilinestring_range(GeometryColumnView const& linestrings_column)
auto const& geometry_offsets = linestrings_column.offsets();
auto const& parts = linestrings_column.child();
auto const& part_offsets = parts.child(0);
auto const& points_xy = parts.child(1).child(1);
auto const& points_xy = parts.child(1).child(1); // Ignores x-y offset {0, 2, 4...}

auto points_it = make_vec_2d_iterator(points_xy.template begin<T>());

Expand Down
59 changes: 57 additions & 2 deletions cpp/include/cuspatial/experimental/ranges/multipoint_range.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <cuspatial/cuda_utils.hpp>
#include <cuspatial/traits.hpp>
#include <cuspatial/types.hpp>

namespace cuspatial {

Expand Down Expand Up @@ -156,7 +157,7 @@ class multipoint_range {
};

/**
* @brief Create a multilinestring_range object of from size and start iterators
* @brief Create a multipoint_range object of from size and start iterators
* @ingroup ranges
*
* @tparam GeometryIteratorDiffType Index type of the size of the geometry array
Expand Down Expand Up @@ -192,7 +193,7 @@ multipoint_range<GeometryIterator, VecIterator> make_multipoint_range(
}

/**
* @brief Create multilinestring_range object from offset and point ranges
* @brief Create multipoint_range object from offset and point ranges
*
* @tparam IntegerRange Range to integers
* @tparam PointRange Range to points
Expand All @@ -208,6 +209,60 @@ auto make_multipoint_range(IntegerRange geometry_offsets, PointRange points)
geometry_offsets.begin(), geometry_offsets.end(), points.begin(), points.end());
}

/**
* @ingroup ranges
* @brief Create a range object of multipoints from cuspatial::geometry_column_view.
* Specialization for points column.
*
* @pre points_column must be a cuspatial::geometry_column_view
*/
template <collection_type_id Type,
typename T,
typename IndexType,
CUSPATIAL_ENABLE_IF(Type == collection_type_id::SINGLE),
typename GeometryColumnView>
auto make_multipoint_range(GeometryColumnView const& points_column)
{
CUSPATIAL_EXPECTS(points_column.geometry_type() == geometry_type_id::POINT,
"Must be POINT geometry type.");
auto geometry_iter = thrust::make_counting_iterator(0);
auto const& points_xy = points_column.child(); // Ignores x-y offset {0, 2, 4...}

auto points_it = make_vec_2d_iterator(points_xy.template begin<T>());

return multipoint_range(geometry_iter,
thrust::next(geometry_iter, points_column.size() + 1),
points_it,
points_it + points_xy.size() / 2);
}

/**
* @ingroup ranges
* @brief Create a range object of multipoints from cuspatial::geometry_column_view.
* Specialization for multipoints column.
*
* @pre multipoints_column must be a cuspatial::geometry_column_view
*/
template <collection_type_id Type,
typename T,
typename IndexType,
CUSPATIAL_ENABLE_IF(Type == collection_type_id::MULTI),
typename GeometryColumnView>
auto make_multipoint_range(GeometryColumnView const& points_column)
{
CUSPATIAL_EXPECTS(points_column.geometry_type() == geometry_type_id::POINT,
"Must be POINT geometry type.");
auto const& geometry_offsets = points_column.offsets();
auto const& points_xy = points_column.child().child(1); // Ignores x-y offset {0, 2, 4...}

auto points_it = make_vec_2d_iterator(points_xy.template begin<T>());

return multipoint_range(geometry_offsets.template begin<IndexType>(),
geometry_offsets.template end<IndexType>(),
points_it,
points_it + points_xy.size() / 2);
};

} // namespace cuspatial

#include <cuspatial/experimental/detail/ranges/multipoint_range.cuh>
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,74 @@ class multipolygon_range {
CUSPATIAL_HOST_DEVICE bool is_valid_segment_id(IndexType1 segment_idx, IndexType2 ring_idx);
};

/**
* @ingroup ranges
* @brief Create a range object of multipolygon from cuspatial::geometry_column_view.
* Specialization for polygons column.
*
* @pre polygons_column must be a cuspatial::geometry_column_view
*/
template <collection_type_id Type,
typename T,
typename IndexType,
typename GeometryColumnView,
CUSPATIAL_ENABLE_IF(Type == collection_type_id::SINGLE)>
auto make_multipolygon_range(GeometryColumnView const& polygons_column)
{
CUSPATIAL_EXPECTS(polygons_column.geometry_type() == geometry_type_id::POLYGON,
"Must be polygon geometry type.");
auto geometry_iter = thrust::make_counting_iterator(0);
auto const& part_offsets = polygons_column.offsets();
auto const& ring_offsets = polygons_column.child().child(0);
auto const& points_xy =
polygons_column.child().child(1).child(1); // Ignores x-y offset {0, 2, 4...}

auto points_it = make_vec_2d_iterator(points_xy.template begin<T>());

return multipolygon_range(geometry_iter,
geometry_iter + part_offsets.size(),
part_offsets.template begin<IndexType>(),
part_offsets.template end<IndexType>(),
ring_offsets.template begin<IndexType>(),
ring_offsets.template end<IndexType>(),
points_it,
points_it + points_xy.size() / 2);
}

/**
* @ingroup ranges
* @brief Create a range object of multipolygon from cuspatial::geometry_column_view.
* Specialization for multipolygons column.
*
* @pre polygon_column must be a cuspatial::geometry_column_view
*/
template <collection_type_id Type,
typename T,
typename IndexType,
CUSPATIAL_ENABLE_IF(Type == collection_type_id::MULTI),
typename GeometryColumnView>
auto make_multipolygon_range(GeometryColumnView const& polygons_column)
{
CUSPATIAL_EXPECTS(polygons_column.geometry_type() == geometry_type_id::POLYGON,
"Must be polygon geometry type.");
auto const& geometry_offsets = polygons_column.offsets();
auto const& part_offsets = polygons_column.child().child(0);
auto const& ring_offsets = polygons_column.child().child(1).child(0);
auto const& points_xy =
polygons_column.child().child(1).child(1).child(1); // Ignores x-y offset {0, 2, 4...}

auto points_it = make_vec_2d_iterator(points_xy.template begin<T>());

return multipolygon_range(geometry_offsets.template begin<IndexType>(),
geometry_offsets.template end<IndexType>(),
part_offsets.template begin<IndexType>(),
part_offsets.template end<IndexType>(),
ring_offsets.template begin<IndexType>(),
ring_offsets.template end<IndexType>(),
points_it,
points_it + points_xy.size() / 2);
};

} // namespace cuspatial

#include <cuspatial/experimental/detail/ranges/multipolygon_range.cuh>
Loading