24 #include "ThirdParty/kdtree-cpp/kdtree.hpp"
26 namespace CrossSectionTableFunctions {
32 template <
typename TLL,
typename TV>
41 const int32_t num_points,
44 static_assert(std::is_same_v<double, TLL>);
45 static_assert(std::is_same_v<float, TV> || std::is_same_v<double, TV>);
52 CHECK_GT(num_points, 1) <<
"num_points must be > 1";
55 if (values.
size() == 0) {
63 VLOG(2) <<
"tf_cross_section_1d: Input raster data has " << values.
size()
70 std::vector<TV> bucket_values(num_points, static_cast<TV>(0));
71 std::vector<int32_t> bucket_counts(num_points, 0);
78 const TLL e1x = line_x2 - line_x1;
79 const TLL e1y = line_y2 - line_y1;
80 const TLL len2_e1 = (e1x * e1x) + (e1y * e1y);
81 int32_t bucket_misses = 0;
82 for (
int i = 0; i < lon.
size(); i++) {
84 const TLL e2x = lon[i] - line_x1;
85 const TLL e2y = lat[i] - line_y1;
86 const TLL dp_e1e2 = (e1x * e2x) + (e1y * e2y);
87 const TLL normalized_distance = dp_e1e2 / len2_e1;
89 auto const bucket_index =
static_cast<int32_t
>(normalized_distance * num_points);
91 if (bucket_index >= 0 && bucket_index < num_points) {
92 bucket_values[bucket_index] += values[i];
93 bucket_counts[bucket_index]++;
100 LOG(
INFO) <<
"tf_cross_section_1d: scatter took " <<
timer_stop(scatter_timer) <<
"ms";
104 <<
"tf_cross_section_1d: had " << bucket_misses <<
" bucket misses";
111 std::vector<double> coords;
112 coords.reserve(num_points * 2);
113 for (
int i = 0; i < num_points; i++) {
114 auto const x =
static_cast<TV
>(i) / static_cast<TV>(num_points - 1);
115 auto const y = bucket_counts[i]
116 ? (bucket_values[i] /
static_cast<TV
>(bucket_counts[i]))
117 :
static_cast<TV
>(0);
123 line[0].fromCoords(coords);
133 template <
typename TLL,
typename TY,
typename TV>
143 const int32_t num_points_x,
144 const int32_t num_points_y,
145 const TLL dwithin_distance,
150 static_assert(std::is_same_v<double, TLL>);
151 static_assert(std::is_same_v<float, TY> || std::is_same_v<double, TY>);
152 static_assert(std::is_same_v<float, TV> || std::is_same_v<double, TV>);
160 CHECK_GT(num_points_x, 1) <<
"num_points_x must be > 1";
161 CHECK_GT(num_points_y, 1) <<
"num_points_y must be > 1";
163 static constexpr
int kNumNearest = 3;
166 if (values.
size() < kNumNearest) {
175 VLOG(2) <<
"tf_cross_section_2d: Input raster data has " << values.
size()
187 auto y_min = std::numeric_limits<double>::max();
188 auto y_max = -std::numeric_limits<double>::max();
190 Kdtree::KdNodeVector nodes(lon.
size());
192 for (
int i = 0; i < lon.
size(); i++) {
194 auto const dlon =
static_cast<double>(lon[i]);
195 auto const dlat =
static_cast<double>(lat[i]);
196 auto const dy =
static_cast<double>(y_axis[i]);
197 n.point = {dlon, dlat, dy};
200 y_min = std::min(dy, y_min);
201 y_max = std::max(dy, y_max);
204 LOG(
INFO) <<
"tf_cross_section_2d: build nodes took " <<
timer_stop(build_nodes_timer)
213 Kdtree::KdTree tree(&nodes);
215 LOG(
INFO) <<
"tf_cross_section_2d: build tree took " <<
timer_stop(build_tree_timer)
222 auto const num_output_rows = num_points_x * num_points_y;
235 auto const max_dist2 = dwithin_distance * dwithin_distance;
237 static constexpr
double kMinDistance2 = 0.0001;
240 tbb::blocked_range<int32_t>(0, num_output_rows),
241 [&](
const tbb::blocked_range<int32_t>& r) {
242 auto const start_idx = r.begin();
243 auto const end_idx = r.end();
244 for (int32_t output_index = start_idx; output_index < end_idx; output_index++) {
246 auto const xi = output_index % num_points_x;
247 auto const yi = output_index / num_points_x;
250 auto const tx =
static_cast<double>(xi) / static_cast<double>(num_points_x - 1);
251 auto const ty =
static_cast<double>(yi) / static_cast<double>(num_points_y - 1);
254 std::vector<double> p{(tx * (line_x2 - line_x1)) + line_x1,
255 (tx * (line_y2 - line_y1)) + line_y1,
256 (ty * (y_max - y_min)) + y_min};
259 Kdtree::KdNodeVector
result;
260 tree.k_nearest_neighbors(p, kNumNearest, &result);
261 CHECK_EQ(result.size(), kNumNearest);
264 int valid_indices[kNumNearest];
265 double valid_weights[kNumNearest];
266 double total_weight = 0.0;
267 size_t num_valid = 0u;
268 for (
size_t i = 0; i < kNumNearest; i++) {
269 auto const dx = result[i].point[0] - p[0];
270 auto const dy = result[i].point[1] - p[1];
271 auto const dist2 = (dx * dx) + (dy * dy);
273 if (dist2 < max_dist2) {
275 auto const dz = result[i].point[2] - p[2];
276 auto const len2 = dist2 + (dz * dz);
277 auto const weight = 1.0 / std::max(len2, kMinDistance2);
279 valid_indices[num_valid] = i;
280 valid_weights[num_valid] = weight;
281 total_weight += weight;
288 if constexpr (std::is_same_v<double, TV>) {
293 if (num_valid > 0u && total_weight > 0.0) {
294 col =
static_cast<TV
>(0.0);
295 const double weight_multiplier = 1.0 / total_weight;
296 for (
size_t i = 0; i < num_valid; i++) {
297 auto const index = valid_indices[i];
298 auto const weight = valid_weights[i];
299 auto const value = values[result[index].index];
300 col +=
static_cast<TV
>(value * weight * weight_multiplier);
305 x[output_index] = tx;
306 y[output_index] = p[2];
307 color[output_index] = col;
311 LOG(
INFO) <<
"tf_cross_section_2d: compute mesh took " <<
timer_stop(compute_mesh_timer)
315 return num_output_rows;
334 template <
typename TLL,
typename TV>
343 const int32_t num_points,
345 return CrossSectionTableFunctions::tf_cross_section_1d_impl<TLL, TV>(
346 mgr, lon, lat, values, line_x1, line_y1, line_x2, line_y2, num_points,
line);
361 template <
typename TLL,
typename TY,
typename TV>
371 const int32_t num_points_x,
372 const int32_t num_points_y,
373 const TLL dwithin_distance,
377 return CrossSectionTableFunctions::tf_cross_section_2d_impl<TLL, TY, TV>(
void set_output_row_size(int64_t num_rows)
int32_t tf_cross_section_1d_impl(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TV > &values, const TLL line_x1, const TLL line_y1, const TLL line_x2, const TLL line_y2, const int32_t num_points, Column< GeoLineString > &line)
void set_output_array_values_total_number(int32_t index, int64_t output_array_values_total_number)
TEMPLATE_NOINLINE int32_t tf_cross_section_1d__cpu_template(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TV > &values, const TLL line_x1, const TLL line_y1, const TLL line_x2, const TLL line_y2, const int32_t num_points, Column< GeoLineString > &line)
int32_t tf_cross_section_2d_impl(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TY > &y_axis, const Column< TV > &values, const TLL line_x1, const TLL line_y1, const TLL line_x2, const TLL line_y2, const int32_t num_points_x, const int32_t num_points_y, const TLL dwithin_distance, Column< TLL > &x, Column< TLL > &y, Column< TV > &color)
DEVICE int64_t size() const
TypeR::rep timer_stop(Type clock_begin)
DEVICE T * getPtr() const
#define LOG_IF(severity, condition)
void set_output_item_values_total_number(int32_t index, int64_t output_item_values_total_number)
void parallel_for(const blocked_range< Int > &range, const Body &body, const Partitioner &p=Partitioner())
TEMPLATE_NOINLINE int32_t tf_cross_section_2d__cpu_template(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TY > &y_axis, const Column< TV > &values, const TLL line_x1, const TLL line_y1, const TLL line_x2, const TLL line_y2, const int32_t num_points_x, const int32_t num_points_y, const TLL dwithin_distance, Column< TLL > &x, Column< TLL > &y, Column< TV > &color)
#define TEMPLATE_NOINLINE