Loading...
Searching...
No Matches
geometry_generator.cuh
1/*
2 * Copyright (c) 2023-2024, NVIDIA CORPORATION.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <cuspatial_test/random.cuh>
20#include <cuspatial_test/vector_factories.cuh>
21
22#include <cuspatial/cuda_utils.hpp>
23#include <cuspatial/error.hpp>
26
27#include <rmm/cuda_stream_view.hpp>
28#include <rmm/device_uvector.hpp>
29#include <rmm/exec_policy.hpp>
30
31#include <thrust/sequence.h>
32#include <thrust/tabulate.h>
33
34#include <ranger/ranger.hpp>
35
36#include <cmath>
37
38namespace cuspatial {
39namespace test {
40
41namespace detail {
42
43template <typename T, typename index_t>
45 vec_2d<T> __device__ operator()(index_t i)
46 {
47 return vec_2d<T>{cos(static_cast<T>(i)), sin(static_cast<T>(i))};
48 }
49};
50
51template <typename T>
53 T segment_length;
54
55 vec_2d<T> __device__ operator()(vec_2d<T> prev, vec_2d<T> rad)
56 {
57 return prev + segment_length * rad;
58 }
59};
60
61} // namespace detail
62
68template <typename T>
70 using element_t = T;
71
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;
76 vec_2d<T> centroid;
77 T radius;
78
79 CUSPATIAL_HOST_DEVICE std::size_t num_polygons()
80 {
81 return num_multipolygons * num_polygons_per_multipolygon;
82 }
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); }
88};
89
103template <typename T>
104vec_2d<T> __device__ generate_ring_coordinate(std::size_t point_local_idx,
105 std::size_t num_edges,
106 vec_2d<T> centroid,
107 T radius)
108{
109 // Overrides last coordinate to make sure ring is closed.
110 if (point_local_idx == num_edges) return vec_2d<T>{centroid.x + radius, centroid.y};
111
112 T angle = (2.0 * M_PI * point_local_idx) / num_edges;
113
114 return vec_2d<T>{centroid.x + radius * cos(angle), centroid.y + radius * sin(angle)};
115}
116
129template <typename T>
130vec_2d<T> __device__ polygon_centroid_displacement(vec_2d<T> centroid,
131 std::size_t part_local_idx,
132 T radius)
133{
134 return centroid + vec_2d<T>{part_local_idx * radius * T{3.0}, T{0.0}};
135}
136
170template <typename T>
171vec_2d<T> __device__
172ring_centroid_displacement(vec_2d<T> centroid, std::size_t ring_local_idx, T radius, T hole_radius)
173{
174 // This is a shell
175 if (ring_local_idx == 0) { return centroid; }
176
177 // This is a hole
178 ring_local_idx -= 1; // offset hole indices to be 0-based
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};
183}
184
196template <typename T, typename MultipolygonRange>
197CUSPATIAL_KERNEL void generate_multipolygon_array_coordinates(
198 MultipolygonRange multipolygons, multipolygon_generator_parameter<T> params)
199{
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);
204
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;
208
209 auto centroid = ring_centroid_displacement(
210 polygon_centroid_displacement(params.centroid, part_local_idx, params.radius),
211 ring_local_idx,
212 params.radius,
213 params.hole_radius());
214
215 if (ring_local_idx == 0) // Generate coordinate for shell
216 multipolygons.point_begin()[idx] = generate_ring_coordinate(
217 point_local_idx, params.num_edges_per_ring, centroid, params.radius);
218 else // Generate coordinate for holes
219 multipolygons.point_begin()[idx] = generate_ring_coordinate(
220 point_local_idx, params.num_edges_per_ring, centroid, params.hole_radius());
221 }
222}
223
232template <typename T>
233auto generate_multipolygon_array(multipolygon_generator_parameter<T> params,
234 rmm::cuda_stream_view stream)
235{
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);
240
241 thrust::sequence(rmm::exec_policy(stream),
242 ring_offsets.begin(),
243 ring_offsets.end(),
244 std::size_t{0},
245 params.num_vertices_per_ring());
246
247 thrust::sequence(rmm::exec_policy(stream),
248 part_offsets.begin(),
249 part_offsets.end(),
250 std::size_t{0},
251 params.num_rings_per_polygon());
252
253 thrust::sequence(rmm::exec_policy(stream),
254 geometry_offsets.begin(),
255 geometry_offsets.end(),
256 std::size_t{0},
257 params.num_polygons_per_multipolygon);
258
259 auto multipolygons = multipolygon_range(geometry_offsets.begin(),
260 geometry_offsets.end(),
261 part_offsets.begin(),
262 part_offsets.end(),
263 ring_offsets.begin(),
264 ring_offsets.end(),
265 coordinates.begin(),
266 coordinates.end());
267
268 auto [tpb, nblocks] = grid_1d(multipolygons.num_points());
269
270 generate_multipolygon_array_coordinates<T><<<nblocks, tpb, 0, stream>>>(multipolygons, params);
271
272 CUSPATIAL_CHECK_CUDA(stream.value());
273
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));
278}
279
285template <typename T>
287 std::size_t num_multilinestrings;
288 std::size_t num_linestrings_per_multilinestring;
289 std::size_t num_segments_per_linestring;
290 T segment_length;
291 vec_2d<T> origin;
292
293 std::size_t num_linestrings()
294 {
295 return num_multilinestrings * num_linestrings_per_multilinestring;
296 }
297
298 std::size_t num_points_per_linestring() { return num_segments_per_linestring + 1; }
299
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(); }
302};
303
327template <typename T>
328auto generate_multilinestring_array(multilinestring_generator_parameter<T> params,
329 rmm::cuda_stream_view stream)
330{
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);
334
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);
340
341 thrust::sequence(rmm::exec_policy(stream),
342 part_offset.begin(),
343 part_offset.end(),
344 static_cast<std::size_t>(0),
345 params.num_segments_per_linestring + 1);
346
347 thrust::tabulate(rmm::exec_policy(stream),
348 points.begin(),
349 points.end(),
351
352 thrust::exclusive_scan(rmm::exec_policy(stream),
353 points.begin(),
354 points.end(),
355 points.begin(),
356 params.origin,
357 detail::random_walk_functor<T>{params.segment_length});
358
359 return make_multilinestring_array<std::size_t, T>(
360 std::move(geometry_offset), std::move(part_offset), std::move(points));
361}
362
368template <typename T>
370 using element_t = T;
371
372 std::size_t num_multipoints;
373 std::size_t num_points_per_multipoints;
374 vec_2d<T> lower_left;
375 vec_2d<T> upper_right;
376
377 CUSPATIAL_HOST_DEVICE std::size_t num_points()
378 {
379 return num_multipoints * num_points_per_multipoints;
380 }
381};
382
391template <typename T>
392auto generate_multipoint_array(multipoint_generator_parameter<T> params,
393 rmm::cuda_stream_view stream)
394{
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);
397
398 thrust::sequence(rmm::exec_policy(stream),
399 offsets.begin(),
400 offsets.end(),
401 std::size_t{0},
402 params.num_points_per_multipoints);
403
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());
407
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);
410
411 auto point_gen =
412 point_generator(params.lower_left, params.upper_right, engine_x, engine_y, x_dist, y_dist);
413
414 thrust::tabulate(rmm::exec_policy(stream), coordinates.begin(), coordinates.end(), point_gen);
415
416 return make_multipoint_array(std::move(offsets), std::move(coordinates));
417}
418
419} // namespace test
420} // namespace cuspatial
#define CUSPATIAL_CHECK_CUDA(stream)
Debug macro to check for CUDA errors.
Definition error.hpp:166
Struct to store the parameters of the multilinestring generator.
Struct to store the parameters of the multipoint aray.
Struct to store the parameters of the multipolygon array generator.