-
Notifications
You must be signed in to change notification settings - Fork 154
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 C++ API for point_linestring_nearest_points
#658
Merged
rapids-bot
merged 75 commits into
rapidsai:branch-22.10
from
isVoid:feature/pairwise_point_to_nearest_linestring_point
Sep 22, 2022
Merged
Changes from all commits
Commits
Show all changes
75 commits
Select commit
Hold shift + click to select a range
de78310
Initial to atomics refactoring
isVoid 6011900
Initial refactoring geometry utilities
isVoid 9761eab
Add header only api
isVoid 2ed60eb
Add cudf column API
isVoid e3ec12d
cmake updates
isVoid a72ac10
inline atomics to avoid compiling RDC
isVoid 31b1e78
Rename to proper naming convention
isVoid f55af2f
make all atomics inline
isVoid e874f3b
Merge branch 'improvement/device_atomics_refactor' into feature/point…
isVoid e9b2ca8
Merge branch 'improvement/geometry_utilities' into feature/point_line…
isVoid f2277f0
Changes header only API to accept only single offset iterator
isVoid 7bc0914
Add header only API tests
isVoid a8ec5ff
Update cudf column API calls
isVoid 1fdfd59
Initial add utility method
isVoid 0274875
Add counting transform iterators
isVoid df286a0
Revert "Update cudf column API calls"
isVoid 688fbb5
Revert "Add cudf column API"
isVoid d0c0c4f
Merge branch 'branch-22.08' of https://github.com/rapidsai/cuspatial …
isVoid 1c4ad61
Update refactored helper locations
isVoid e4038a5
Add cudf column API
isVoid 5004bbe
Add equality test utility and fix header only tests
isVoid 986dbb2
minor docstring updates
isVoid 2feab4b
Add cudf column API documentation
isVoid 5e07194
Include point-linestring distance files in docs.
isVoid 4834aa2
Apply suggestions from code review
isVoid de0feb7
Address review comments
isVoid c897974
Merge branch 'feature/header_only_point_linestring_distance' of githu…
isVoid 6dc34e0
Merge branch 'branch-22.10' of https://github.com/rapidsai/cuspatial …
isVoid 624a97f
Fix broken builds
isVoid 7d8b4b6
Initial scaffolding for nearest point
isVoid 488ab7a
refactor primitives
isVoid 26a6c6a
Initial implementation of kernel
isVoid 8165c68
Check CUDA Error after launch
isVoid 37de419
Assert multi-point, multi-linestring format
isVoid 924ef59
Add `interleaved_iterator_to_vec_2d_iterator`
isVoid 999d5d7
Multi-geom implementation
isVoid 164fd68
Flesh out cudf column API
isVoid faeff0e
rename header only API iterators
isVoid 4729e4d
Merge branch 'branch-22.10' of https://github.com/rapidsai/cuspatial …
isVoid d34ee82
Fixes tuple construction in helper
isVoid 59a2207
Variable renames, adds static asserts
isVoid aa39cdc
Adds vec2d to interleaved transformer
isVoid 529d7b2
Variable renames, use interleaved iterator transformer
isVoid 7e1dffe
Adds simple test, vector of vec2d equivalence test utility
isVoid 50bfd25
fix end of segment access, writes intra-index not global index to res…
isVoid fde05b8
Merge branch 'branch-22.10' of https://github.com/rapidsai/cuspatial …
isVoid afae694
docstring for column API
isVoid 55411a4
Update to also return multipoint index when needed
isVoid 35a661b
Add column API impl to cmake
isVoid ff8be26
Update header only API tests to accomodate the new return type
isVoid 50a2aea
use `constexpr` instead
isVoid a2240ed
Make column API device span const access
isVoid b0c3665
Add column API tests
isVoid 93d6c5f
Add invalid input tests
isVoid 281b972
Bug: min distance squared should be initialized for all points of a m…
isVoid b4e1c47
Bug: return coordinate array should be npairs*2; geometry array lengt…
isVoid 9f260f7
MInor test fixes
isVoid 7863a3e
Rename launch functor
isVoid 633cdaa
Write throws in docstring
isVoid 979611b
Update header only API docs
isVoid f3f52dc
Add docstring for kernel
isVoid 6701d64
Typo
isVoid 6e3d785
Rename the function as `nearest_points`
isVoid 15af211
Merge branch 'branch-22.10' of https://github.com/rapidsai/cuspatial …
isVoid 6c13809
use latest vector<vec_2d> matcher
isVoid 946bd10
Merge branch 'branch-22.10' of https://github.com/rapidsai/cuspatial …
isVoid cb80449
replace tuple with custom struct
isVoid 1c8ea50
rename column API file and add API to doc page
isVoid fceafaf
fix tests after rename
isVoid ce1d8b7
address review comments in bulk
isVoid 9dd1a1e
revert the use of thrust::tuple
isVoid f72ef3d
Add two tests for nearest end points
isVoid 3fba1c4
add more corner case tests
isVoid ed1bf28
Apply suggestions from code review
isVoid 8f5d7c1
style
isVoid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
173 changes: 173 additions & 0 deletions
173
cpp/include/cuspatial/experimental/detail/point_linestring_nearest_points.cuh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/* | ||
* 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/detail/utility/device_atomics.cuh> | ||
#include <cuspatial/detail/utility/linestring.cuh> | ||
#include <cuspatial/error.hpp> | ||
#include <cuspatial/traits.hpp> | ||
#include <cuspatial/vec_2d.hpp> | ||
|
||
#include <rmm/cuda_stream_view.hpp> | ||
#include <rmm/exec_policy.hpp> | ||
|
||
#include <thrust/binary_search.h> | ||
|
||
#include <iterator> | ||
#include <limits> | ||
#include <memory> | ||
#include <type_traits> | ||
|
||
namespace cuspatial { | ||
namespace detail { | ||
|
||
/** | ||
* @internal | ||
* @brief Kernel to compute the nearest point between a multipoint and multilinestring | ||
* | ||
* See header only API for input parameter definitions. | ||
* | ||
* Each thread computes the nearest point between a pair of multipoint and multilinestring. | ||
* The minimum distance between the geometries are stored in `min_distance_squared` and updated | ||
* when smaller is encountered. `linestring.cuh::point_to_segment_distance_squared_nearest_point` | ||
* is used to compute the nearest point on the segment and its distance to the test point. | ||
*/ | ||
template <class Vec2dItA, | ||
class Vec2dItB, | ||
class OffsetIteratorA, | ||
class OffsetIteratorB, | ||
class OffsetIteratorC, | ||
class OutputIt> | ||
void __global__ | ||
pairwise_point_linestring_nearest_points_kernel(OffsetIteratorA points_geometry_offsets_first, | ||
OffsetIteratorA points_geometry_offsets_last, | ||
Vec2dItA points_first, | ||
Vec2dItA points_last, | ||
OffsetIteratorB linestring_geometry_offsets_first, | ||
OffsetIteratorB linestring_geometry_offsets_last, | ||
OffsetIteratorC linestring_part_offsets_first, | ||
OffsetIteratorC linestring_part_offsets_last, | ||
Vec2dItB linestring_points_first, | ||
Vec2dItB linestring_points_last, | ||
OutputIt output_first) | ||
{ | ||
using T = iterator_vec_base_type<Vec2dItA>; | ||
using IndexType = iterator_value_type<OffsetIteratorA>; | ||
|
||
auto num_pairs = | ||
thrust::distance(points_geometry_offsets_first, points_geometry_offsets_last) - 1; | ||
auto num_linestring_points = thrust::distance(linestring_points_first, linestring_points_last); | ||
|
||
for (auto idx = threadIdx.x + blockIdx.x * blockDim.x; idx < num_pairs; | ||
idx += gridDim.x * blockDim.x) { | ||
IndexType nearest_point_idx; | ||
IndexType nearest_part_idx; | ||
IndexType nearest_segment_idx; | ||
vec_2d<T> nearest_point; | ||
|
||
T min_distance_squared = std::numeric_limits<T>::max(); | ||
IndexType point_start = points_geometry_offsets_first[idx]; | ||
IndexType point_end = points_geometry_offsets_first[idx + 1]; | ||
for (auto point_idx = point_start; point_idx < point_end; point_idx++) { | ||
IndexType linestring_parts_start = linestring_geometry_offsets_first[idx]; | ||
IndexType linestring_parts_end = linestring_geometry_offsets_first[idx + 1]; | ||
|
||
for (auto part_idx = linestring_parts_start; part_idx < linestring_parts_end; part_idx++) { | ||
IndexType segment_start = linestring_part_offsets_first[part_idx]; | ||
// The last point of the linestring does not form a segment | ||
IndexType segment_end = linestring_part_offsets_first[part_idx + 1] - 1; | ||
|
||
for (auto segment_idx = segment_start; segment_idx < segment_end; segment_idx++) { | ||
vec_2d<T> c = points_first[point_idx]; | ||
vec_2d<T> a = linestring_points_first[segment_idx]; | ||
vec_2d<T> b = linestring_points_first[segment_idx + 1]; | ||
|
||
auto distance_nearest_point_pair = | ||
point_to_segment_distance_squared_nearest_point(c, a, b); | ||
auto distance_squared = thrust::get<0>(distance_nearest_point_pair); | ||
if (distance_squared < min_distance_squared) { | ||
min_distance_squared = distance_squared; | ||
nearest_point_idx = point_idx - point_start; | ||
nearest_part_idx = part_idx - linestring_parts_start; | ||
nearest_segment_idx = segment_idx - segment_start; | ||
nearest_point = thrust::get<1>(distance_nearest_point_pair); | ||
} | ||
} | ||
} | ||
} | ||
output_first[idx] = | ||
thrust::make_tuple(nearest_point_idx, nearest_part_idx, nearest_segment_idx, nearest_point); | ||
} | ||
} | ||
|
||
} // namespace detail | ||
|
||
template <class Vec2dItA, | ||
class Vec2dItB, | ||
class OffsetIteratorA, | ||
class OffsetIteratorB, | ||
class OffsetIteratorC, | ||
class OutputIt> | ||
OutputIt pairwise_point_linestring_nearest_points(OffsetIteratorA points_geometry_offsets_first, | ||
OffsetIteratorA points_geometry_offsets_last, | ||
Vec2dItA points_first, | ||
Vec2dItA points_last, | ||
OffsetIteratorB linestring_geometry_offsets_first, | ||
OffsetIteratorC linestring_part_offsets_first, | ||
OffsetIteratorC linestring_part_offsets_last, | ||
Vec2dItB linestring_points_first, | ||
Vec2dItB linestring_points_last, | ||
OutputIt output_first, | ||
rmm::cuda_stream_view stream) | ||
{ | ||
using T = iterator_vec_base_type<Vec2dItA>; | ||
|
||
static_assert(is_same_floating_point<T, iterator_vec_base_type<Vec2dItB>>(), | ||
"Coordinates must be the same floating point type."); | ||
|
||
static_assert(is_same<vec_2d<T>, iterator_value_type<Vec2dItA>, iterator_value_type<Vec2dItB>>(), | ||
"Inputs must be cuspatial::vec_2d<T>"); | ||
|
||
auto num_pairs = std::distance(points_geometry_offsets_first, points_geometry_offsets_last) - 1; | ||
|
||
if (num_pairs == 0) return output_first; | ||
|
||
std::size_t constexpr threads_per_block = 256; | ||
std::size_t const num_blocks = (num_pairs + threads_per_block - 1) / threads_per_block; | ||
|
||
detail::pairwise_point_linestring_nearest_points_kernel<<<num_blocks, | ||
threads_per_block, | ||
0, | ||
stream.value()>>>( | ||
points_geometry_offsets_first, | ||
points_geometry_offsets_last, | ||
points_first, | ||
points_last, | ||
linestring_geometry_offsets_first, | ||
linestring_geometry_offsets_first + num_pairs + 1, | ||
linestring_part_offsets_first, | ||
linestring_part_offsets_last, | ||
linestring_points_first, | ||
linestring_points_last, | ||
output_first); | ||
|
||
CUSPATIAL_CUDA_TRY(cudaGetLastError()); | ||
|
||
return output_first + num_pairs; | ||
} | ||
|
||
} // namespace cuspatial |
103 changes: 103 additions & 0 deletions
103
cpp/include/cuspatial/experimental/point_linestring_nearest_points.cuh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* 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 <rmm/cuda_stream_view.hpp> | ||
|
||
namespace cuspatial { | ||
|
||
/** | ||
* @brief Compute the nearest points and geometry ID between pairs of multipoint and | ||
* multilinestring | ||
* | ||
* The nearest point from a test point to a linestring is a point on the linestring that has | ||
* the shortest distance to the test point compared to any other points on the linestring. | ||
* | ||
* The nearest point from a test multipoint to a multilinestring is the nearest point that | ||
* has the shortest distance in all pairs of points and linestrings. | ||
* | ||
* In addition, this API writes these geometry and part ID where the nearest point locates to output | ||
* iterators: | ||
* - The point ID indicates which point in the multipoint is the nearest point. | ||
* - The linestring ID is the offset within the multilinestring that contains the nearest point. | ||
* - The segment ID is the offset within the linestring of the segment that contains the nearest | ||
* point. It is the same as the ID of the starting point of the segment. | ||
* | ||
* @tparam Cart2dItA iterator type for point array of the point element of each pair. Must meet | ||
* the requirements of [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. | ||
* @tparam Cart2dItB iterator type for point array of the linestring element of each pair. Must meet | ||
* the requirements of [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. | ||
* @tparam OffsetIteratorA iterator type for `point_geometry_offset` array. Must meet the | ||
* requirements of [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. | ||
* @tparam OffsetIteratorB iterator type for `linestring_geometry_offset` array. Must meet the | ||
* requirements of [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. | ||
* @tparam OffsetIteratorC iterator type for `linestring_part_offset` array. Must meet the | ||
* requirements of [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. | ||
* @tparam OutputIt iterator type for output array. Must meet the requirements of | ||
* [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. | ||
isVoid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* @param point_geometry_offset_first beginning of the range of multipoint geometries of each | ||
* pair | ||
* @param point_geometry_offset_last end of the range of multipoint geometries of each pair | ||
* @param points_first beginning of the range of point values | ||
* @param points_last end of the range of the point values | ||
* @param linestring_geometry_offset_first beginning of the range of offsets to the multilinestring | ||
* geometry of each pair, the end range is implied by linestring_geometry_offset_first + | ||
* std::distance(`point_geometry_offset_first`, `point_geometry_offset_last`) | ||
* @param linestring_offsets_first beginning of the range of offsets to the starting point | ||
* of each linestring | ||
* @param linestring_offsets_last end of the range of offsets to the starting point | ||
* of each linestring | ||
* @param linestring_points_first beginning of the range of linestring points | ||
* @param linestring_points_last end of the range of linestring points | ||
* @param output_first A zipped-iterator of 4 outputs. The first element should be compatible | ||
* with iterator_value_type<OffsetIteratorA>, stores the geometry ID of the nearest point in | ||
* multipoint. The second element should be compatible with iterator_value_type<OffsetIteratorB>, | ||
* stores the geometry ID of the nearest linestring. The third element should be compatible with | ||
* iterator_value_type<OffsetIteratorC>, stores the part ID to the nearest segment. The forth | ||
* element should be compatible with vec_2d, stores the coordinate of the nearest point on the | ||
* (multi)linestring. | ||
* @param stream The CUDA stream to use for device memory operations and kernel launches. | ||
* @return Output iterator to the element past the last tuple computed. | ||
* | ||
* @pre all input iterators for coordinates must have `cuspatial::vec_2d` type, | ||
* and must have the same base floating point type. | ||
* | ||
* [LinkLRAI]: https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator | ||
* "LegacyRandomAccessIterator" | ||
*/ | ||
template <class Vec2dItA, | ||
class Vec2dItB, | ||
class OffsetIteratorA, | ||
class OffsetIteratorB, | ||
class OffsetIteratorC, | ||
class OutputIt> | ||
OutputIt pairwise_point_linestring_nearest_points( | ||
OffsetIteratorA points_geometry_offsets_first, | ||
OffsetIteratorA points_geometry_offsets_last, | ||
Vec2dItA points_first, | ||
Vec2dItA points_last, | ||
OffsetIteratorB linestring_geometry_offsets_first, | ||
OffsetIteratorC linestring_part_offsets_first, | ||
OffsetIteratorC linestring_part_offsets_last, | ||
Vec2dItB linestring_points_first, | ||
Vec2dItB linestring_points_last, | ||
OutputIt output_first, | ||
rmm::cuda_stream_view stream = rmm::cuda_stream_default); | ||
} // namespace cuspatial | ||
|
||
#include <cuspatial/experimental/detail/point_linestring_nearest_points.cuh> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing this quadruple nested loop, I see now how important it will be to add automatic geometry iterators that know how to do the nested indexing. You want to be able to just iterate over the pairs, and for each pair, just have a for_each over the points and a nested for_each over the points of the multilinestring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, abstracting different level of iteration is direly needed. Perhaps we can continue the discussion in #677 ?