19#include <cuspatial_test/random.cuh>
20#include <cuspatial_test/vector_factories.cuh>
22#include <cuspatial/cuda_utils.hpp>
27#include <rmm/cuda_stream_view.hpp>
28#include <rmm/device_uvector.hpp>
29#include <rmm/exec_policy.hpp>
31#include <thrust/sequence.h>
32#include <thrust/tabulate.h>
34#include <ranger/ranger.hpp>
43template <
typename T,
typename index_t>
45 vec_2d<T> __device__ operator()(index_t i)
47 return vec_2d<T>{cos(
static_cast<T
>(i)), sin(
static_cast<T
>(i))};
57 return prev + segment_length * rad;
72 std::size_t num_multipolygons;
73 std::size_t num_polygons_per_multipolygon;
74 std::size_t num_holes_per_polygon;
75 std::size_t num_edges_per_ring;
79 CUSPATIAL_HOST_DEVICE std::size_t num_polygons()
81 return num_multipolygons * num_polygons_per_multipolygon;
83 CUSPATIAL_HOST_DEVICE std::size_t num_rings() {
return num_polygons() * num_rings_per_polygon(); }
84 CUSPATIAL_HOST_DEVICE std::size_t num_coords() {
return num_rings() * num_vertices_per_ring(); }
85 CUSPATIAL_HOST_DEVICE std::size_t num_vertices_per_ring() {
return num_edges_per_ring + 1; }
86 CUSPATIAL_HOST_DEVICE std::size_t num_rings_per_polygon() {
return num_holes_per_polygon + 1; }
87 CUSPATIAL_HOST_DEVICE T hole_radius() {
return radius / (num_holes_per_polygon + 1); }
104vec_2d<T> __device__ generate_ring_coordinate(std::size_t point_local_idx,
105 std::size_t num_edges,
110 if (point_local_idx == num_edges)
return vec_2d<T>{centroid.x + radius, centroid.y};
112 T angle = (2.0 * M_PI * point_local_idx) / num_edges;
114 return vec_2d<T>{centroid.x + radius * cos(angle), centroid.y + radius * sin(angle)};
130vec_2d<T> __device__ polygon_centroid_displacement(vec_2d<T> centroid,
131 std::size_t part_local_idx,
134 return centroid + vec_2d<T>{part_local_idx * radius * T{3.0}, T{0.0}};
172ring_centroid_displacement(vec_2d<T> centroid, std::size_t ring_local_idx, T radius, T hole_radius)
175 if (ring_local_idx == 0) {
return centroid; }
179 T max_hole_displacement = radius - hole_radius;
180 T displacement_x = -max_hole_displacement + ring_local_idx * hole_radius * 2;
181 T displacement_y = 0.0;
182 return centroid + vec_2d<T>{displacement_x, displacement_y};
196template <
typename T,
typename MultipolygonRange>
197CUSPATIAL_KERNEL
void generate_multipolygon_array_coordinates(
200 for (
auto idx : ranger::grid_stride_range(multipolygons.num_points())) {
201 auto ring_idx = multipolygons.ring_idx_from_point_idx(idx);
202 auto part_idx = multipolygons.part_idx_from_ring_idx(ring_idx);
203 auto geometry_idx = multipolygons.geometry_idx_from_part_idx(part_idx);
205 auto point_local_idx = idx - params.num_vertices_per_ring() * ring_idx;
206 auto ring_local_idx = ring_idx - params.num_rings_per_polygon() * part_idx;
207 auto part_local_idx = part_idx - params.num_polygons_per_multipolygon * geometry_idx;
209 auto centroid = ring_centroid_displacement(
210 polygon_centroid_displacement(params.centroid, part_local_idx, params.radius),
213 params.hole_radius());
215 if (ring_local_idx == 0)
216 multipolygons.point_begin()[idx] = generate_ring_coordinate(
217 point_local_idx, params.num_edges_per_ring, centroid, params.radius);
219 multipolygons.point_begin()[idx] = generate_ring_coordinate(
220 point_local_idx, params.num_edges_per_ring, centroid, params.hole_radius());
234 rmm::cuda_stream_view stream)
236 rmm::device_uvector<std::size_t> geometry_offsets(params.num_multipolygons + 1, stream);
237 rmm::device_uvector<std::size_t> part_offsets(params.num_polygons() + 1, stream);
238 rmm::device_uvector<std::size_t> ring_offsets(params.num_rings() + 1, stream);
239 rmm::device_uvector<vec_2d<T>> coordinates(params.num_coords(), stream);
241 thrust::sequence(rmm::exec_policy(stream),
242 ring_offsets.begin(),
245 params.num_vertices_per_ring());
247 thrust::sequence(rmm::exec_policy(stream),
248 part_offsets.begin(),
251 params.num_rings_per_polygon());
253 thrust::sequence(rmm::exec_policy(stream),
254 geometry_offsets.begin(),
255 geometry_offsets.end(),
257 params.num_polygons_per_multipolygon);
259 auto multipolygons = multipolygon_range(geometry_offsets.begin(),
260 geometry_offsets.end(),
261 part_offsets.begin(),
263 ring_offsets.begin(),
268 auto [tpb, nblocks] = grid_1d(multipolygons.num_points());
270 generate_multipolygon_array_coordinates<T><<<nblocks, tpb, 0, stream>>>(multipolygons, params);
274 return make_multipolygon_array<std::size_t, vec_2d<T>>(std::move(geometry_offsets),
275 std::move(part_offsets),
276 std::move(ring_offsets),
277 std::move(coordinates));
287 std::size_t num_multilinestrings;
288 std::size_t num_linestrings_per_multilinestring;
289 std::size_t num_segments_per_linestring;
293 std::size_t num_linestrings()
295 return num_multilinestrings * num_linestrings_per_multilinestring;
298 std::size_t num_points_per_linestring() {
return num_segments_per_linestring + 1; }
300 std::size_t num_segments() {
return num_linestrings() * num_segments_per_linestring; }
301 std::size_t num_points() {
return num_linestrings() * num_points_per_linestring(); }
329 rmm::cuda_stream_view stream)
331 rmm::device_uvector<std::size_t> geometry_offset(params.num_multilinestrings + 1, stream);
332 rmm::device_uvector<std::size_t> part_offset(params.num_linestrings() + 1, stream);
333 rmm::device_uvector<vec_2d<T>> points(params.num_points(), stream);
335 thrust::sequence(rmm::exec_policy(stream),
336 geometry_offset.begin(),
337 geometry_offset.end(),
338 static_cast<std::size_t
>(0),
339 params.num_linestrings_per_multilinestring);
341 thrust::sequence(rmm::exec_policy(stream),
344 static_cast<std::size_t
>(0),
345 params.num_segments_per_linestring + 1);
347 thrust::tabulate(rmm::exec_policy(stream),
352 thrust::exclusive_scan(rmm::exec_policy(stream),
359 return make_multilinestring_array<std::size_t, T>(
360 std::move(geometry_offset), std::move(part_offset), std::move(points));
372 std::size_t num_multipoints;
373 std::size_t num_points_per_multipoints;
377 CUSPATIAL_HOST_DEVICE std::size_t num_points()
379 return num_multipoints * num_points_per_multipoints;
393 rmm::cuda_stream_view stream)
395 rmm::device_uvector<vec_2d<T>> coordinates(params.num_points(), stream);
396 rmm::device_uvector<std::size_t> offsets(params.num_multipoints + 1, stream);
398 thrust::sequence(rmm::exec_policy(stream),
402 params.num_points_per_multipoints);
404 auto golden_ratio = (1 + std::sqrt(T{5})) / 2;
405 auto engine_x = deterministic_engine(golden_ratio * params.num_points());
406 auto engine_y = deterministic_engine((1 / golden_ratio) * params.num_points());
408 auto x_dist = make_uniform_dist(params.lower_left.x, params.upper_right.x);
409 auto y_dist = make_uniform_dist(params.lower_left.y, params.upper_right.y);
412 point_generator(params.lower_left, params.upper_right, engine_x, engine_y, x_dist, y_dist);
414 thrust::tabulate(rmm::exec_policy(stream), coordinates.begin(), coordinates.end(), point_gen);
416 return make_multipoint_array(std::move(offsets), std::move(coordinates));
#define CUSPATIAL_CHECK_CUDA(stream)
检查 CUDA 错误的调试宏。