23 #include "cpl_string.h"
26 #include "gdal_version.h"
28 #include "ogr_srs_api.h"
30 #include "ogrsf_frmts.h"
32 namespace GDALTableFunctions {
38 template <
typename TV,
typename TG>
40 const int32_t raster_width,
41 const int32_t raster_height,
42 const double affine_transform[6],
44 const TV contour_interval,
45 const TV contour_offset,
49 static_assert(std::is_same_v<float, TV> || std::is_same_v<double, TV>);
50 static_assert(std::is_same_v<GeoLineString, TG> || std::is_same_v<GeoPolygon, TG>);
53 std::string value_type_str;
56 if constexpr (std::is_same_v<float, TV>) {
57 value_type_str =
"Float32";
58 pixel_offset =
sizeof(float);
59 null_value =
static_cast<double>(std::numeric_limits<float>::min());
60 }
else if constexpr (std::is_same_v<double, TV>) {
61 value_type_str =
"Float64";
62 pixel_offset =
sizeof(double);
63 null_value = std::numeric_limits<double>::min();
65 CHECK(value_type_str.length());
67 auto const num_values = raster_width * raster_height;
68 VLOG(2) <<
"tf_raster_contour: Final raster data has " << num_values <<
" values, min "
69 << *std::min_element(values, values + num_values) <<
", max "
70 << *std::max_element(values, values + num_values);
73 constexpr
bool is_polygons = std::is_same_v<GeoPolygon, TG>;
76 std::stringstream mem_ss;
77 mem_ss <<
"MEM:::DATAPOINTER=" << std::hex << values << std::dec
78 <<
",PIXELS=" << raster_width <<
",LINES=" << raster_height
79 <<
",BANDS=1,DATATYPE=" << value_type_str <<
",PIXELOFFSET=" << pixel_offset
80 <<
",GEOTRANSFORM=" << affine_transform[0] <<
"/" << affine_transform[1] <<
"/"
81 << affine_transform[2] <<
"/" << affine_transform[3] <<
"/"
82 << affine_transform[4] <<
"/" << affine_transform[5];
83 std::string mem_str = mem_ss.str();
89 char** options =
nullptr;
90 GDALDatasetH raster_ds =
nullptr;
91 GDALDataset* vector_ds =
nullptr;
94 ScopeGuard cleanup = [options, raster_ds, vector_ds]() {
102 GDALClose(vector_ds);
107 raster_ds = GDALOpen(mem_str.c_str(), GA_ReadOnly);
111 auto raster_band = GDALGetRasterBand(raster_ds, 1);
115 auto* memory_driver = GetGDALDriverManager()->GetDriverByName(
"Memory");
116 CHECK(memory_driver);
119 vector_ds = memory_driver->Create(
"contours", 0, 0, 0, GDT_Unknown, NULL);
123 OGRSpatialReference spatial_reference;
124 spatial_reference.importFromEPSG(4326);
125 spatial_reference.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
129 vector_ds->CreateLayer(
"lines", &spatial_reference, wkbLineString, NULL);
133 int contour_min_field_index{-1};
134 int contour_max_field_index{-1};
135 int contour_val_field_index{-1};
137 OGRFieldDefn contour_min_field_defn(
"contour_min", OFTReal);
138 vector_layer->CreateField(&contour_min_field_defn);
139 contour_min_field_index = vector_layer->FindFieldIndex(
"contour_min", TRUE);
140 CHECK_GE(contour_min_field_index, 0);
141 OGRFieldDefn contour_max_field_defn(
"contour_max", OFTReal);
142 vector_layer->CreateField(&contour_max_field_defn);
143 contour_max_field_index = vector_layer->FindFieldIndex(
"contour_max", TRUE);
144 CHECK_GE(contour_max_field_index, 0);
146 OGRFieldDefn contour_val_field_defn(
"contour_val", OFTReal);
147 vector_layer->CreateField(&contour_val_field_defn);
148 contour_val_field_index = vector_layer->FindFieldIndex(
"contour_val", TRUE);
149 CHECK_GE(contour_val_field_index, 0);
153 if constexpr (is_polygons) {
154 options = CSLAppendPrintf(options,
"ELEV_FIELD_MIN=%d", contour_min_field_index);
155 options = CSLAppendPrintf(options,
"ELEV_FIELD_MAX=%d", contour_max_field_index);
157 options = CSLAppendPrintf(options,
"ELEV_FIELD=%d", contour_val_field_index);
160 CSLAppendPrintf(options,
"LEVEL_INTERVAL=%f", static_cast<float>(contour_interval));
161 options = CSLAppendPrintf(options,
"LEVEL_BASE=%f", static_cast<float>(contour_offset));
162 options = CSLAppendPrintf(options,
"NODATA=%.19g", null_value);
163 if constexpr (is_polygons) {
164 options = CSLAppendPrintf(options,
"POLYGONIZE=YES");
169 GDALContourGenerateEx(raster_band, vector_layer, options,
nullptr,
nullptr);
171 return mgr.ERROR_MESSAGE(
"Contour generation failed");
175 vector_ds->ResetReading();
178 auto const num_features =
static_cast<int32_t
>(vector_layer->GetFeatureCount());
180 VLOG(1) <<
"tf_raster_contour: GDAL generated " << num_features <<
" features";
183 if (num_features == 0) {
192 int64_t total_num_points{};
193 int32_t num_output_features{};
195 vector_layer->ResetReading();
198 for (int32_t i = 0; i < num_features; i++) {
203 auto const* geometry = feature->GetGeometryRef();
207 auto const geometry_wkb_type = wkbFlatten(geometry->getGeometryType());
209 if constexpr (is_polygons) {
211 if (geometry_wkb_type != wkbMultiPolygon) {
212 return mgr.ERROR_MESSAGE(
"Geometry WKB type is not MultiPolygon");
216 auto const* multipolygon_geometry =
dynamic_cast<const OGRMultiPolygon*
>(geometry);
217 CHECK(multipolygon_geometry);
220 auto const num_geometries = multipolygon_geometry->getNumGeometries();
221 for (
auto p = 0; p < num_geometries; p++) {
223 auto const* polygon_geometry =
224 dynamic_cast<const OGRPolygon*
>(multipolygon_geometry->getGeometryRef(p));
225 CHECK(polygon_geometry);
228 auto const* exterior_ring = polygon_geometry->getExteriorRing();
229 CHECK(exterior_ring);
230 total_num_points += exterior_ring->getNumPoints();
233 for (
auto r = 0; r < polygon_geometry->getNumInteriorRings(); r++) {
234 auto const* interior_ring = polygon_geometry->getInteriorRing(r);
235 CHECK(interior_ring);
236 total_num_points += interior_ring->getNumPoints();
240 num_output_features++;
244 if (geometry_wkb_type != wkbLineString) {
245 return mgr.ERROR_MESSAGE(
"Geometry WKB type is not Linestring");
249 auto const* linestring_geometry =
dynamic_cast<const OGRLineString*
>(geometry);
250 CHECK(linestring_geometry);
253 total_num_points += linestring_geometry->getNumPoints();
256 num_output_features++;
260 VLOG(1) <<
"tf_raster_contour: Total points " << total_num_points;
269 int64_t output_feature_index{};
271 vector_layer->ResetReading();
274 for (int32_t i = 0; i < num_features; i++) {
279 auto const* geometry = feature->GetGeometryRef();
282 if constexpr (is_polygons) {
284 auto const* multipolygon_geometry =
dynamic_cast<const OGRMultiPolygon*
>(geometry);
285 CHECK(multipolygon_geometry);
288 auto const num_geometries = multipolygon_geometry->getNumGeometries();
289 for (
auto p = 0; p < num_geometries; p++) {
291 auto const* polygon_geometry =
292 dynamic_cast<const OGRPolygon*
>(multipolygon_geometry->getGeometryRef(p));
293 CHECK(polygon_geometry);
296 std::vector<std::vector<double>> coords;
298 std::vector<double> ring_coords;
299 auto const* exterior_ring = polygon_geometry->getExteriorRing();
300 CHECK(exterior_ring);
301 for (
int j = 0; j < exterior_ring->getNumPoints(); j++) {
303 exterior_ring->getPoint(j, &point);
304 ring_coords.push_back(point.getX());
305 ring_coords.push_back(point.getY());
307 coords.push_back(ring_coords);
309 for (
auto r = 0; r < polygon_geometry->getNumInteriorRings(); r++) {
310 auto const* interior_ring = polygon_geometry->getInteriorRing(r);
311 CHECK(interior_ring);
312 std::vector<double> ring_coords;
313 for (
int j = 0; j < interior_ring->getNumPoints(); j++) {
315 interior_ring->getPoint(j, &point);
316 ring_coords.push_back(point.getX());
317 ring_coords.push_back(point.getY());
319 coords.push_back(ring_coords);
323 auto status = contour_features[output_feature_index].fromCoords(coords);
324 if (status != FlatBufferManager::Status::Success) {
325 return mgr.ERROR_MESSAGE(
"fromCoords failed: " + ::
toString(status));
331 auto const contour_min =
332 static_cast<TV
>(feature->GetFieldAsDouble(contour_min_field_index));
333 auto const contour_max =
334 static_cast<TV
>(feature->GetFieldAsDouble(contour_max_field_index));
335 contour_values[output_feature_index] = (contour_min ==
static_cast<TV
>(0))
336 ? (contour_max - contour_interval)
340 output_feature_index++;
344 auto const* linestring_geometry =
dynamic_cast<const OGRLineString*
>(geometry);
345 CHECK(linestring_geometry);
348 std::vector<double> coords;
349 for (
int j = 0; j < linestring_geometry->getNumPoints(); j++) {
351 linestring_geometry->getPoint(j, &point);
352 coords.push_back(point.getX());
353 coords.push_back(point.getY());
357 contour_features[output_feature_index].fromCoords(coords);
360 contour_values[output_feature_index] =
361 static_cast<TV
>(feature->GetFieldAsDouble(contour_val_field_index));
364 output_feature_index++;
368 VLOG(1) <<
"tf_raster_contour: Output " << num_features <<
" features";
371 return num_output_features;
378 template <
typename TLL,
typename TV,
typename TG>
384 const float bin_dim_meters,
385 const int32_t neighborhood_fill_radius,
386 const bool fill_only_nulls,
388 const bool flip_latitude,
389 const TV contour_interval,
390 const TV contour_offset,
395 CHECK_GE(neighborhood_fill_radius, 0);
396 CHECK_GT(contour_interval, static_cast<TV>(0));
401 auto const error_msg =
"Invalid Raster Aggregate Type: " + agg_type.
getString();
402 return mgr.ERROR_MESSAGE(error_msg);
406 auto const error_msg =
407 "Invalid Raster Fill Aggregate Type: " + fill_agg_type.
getString();
408 return mgr.ERROR_MESSAGE(error_msg);
411 VLOG(2) <<
"tf_raster_contour: Input raster data has " << values.
size()
417 std::unique_ptr<GeoRaster<TLL, TV>> geo_raster;
419 geo_raster = std::make_unique<GeoRaster<TLL, TV>>(
420 lon, lat, values, raster_agg_type, bin_dim_meters,
true,
true);
422 }
catch (std::runtime_error& e) {
425 geo_raster =
nullptr;
429 if (!geo_raster || geo_raster->num_x_bins_ < 1 || geo_raster->num_y_bins_ < 1) {
430 VLOG(1) <<
"tf_raster_contour: No input raster data. Cannot compute contours.";
437 if (neighborhood_fill_radius > 0) {
438 geo_raster->fill_bins_from_neighbors(
439 neighborhood_fill_radius, fill_only_nulls, raster_fill_agg_type);
442 auto const raster_width =
static_cast<int32_t
>(geo_raster->num_x_bins_);
443 auto const raster_height =
static_cast<int32_t
>(geo_raster->num_y_bins_);
444 auto const lon_min =
static_cast<double>(geo_raster->x_min_);
445 auto const lat_min =
static_cast<double>(geo_raster->y_min_);
446 auto const lon_bin_scale =
static_cast<double>(geo_raster->x_scale_input_to_bin_);
447 auto const lat_bin_scale =
static_cast<double>(geo_raster->y_scale_input_to_bin_);
450 if (lon_bin_scale <= 0.0 || lat_bin_scale <= 0.0) {
451 return mgr.ERROR_MESSAGE(
"Invalid input raster scale. Cannot compute contours.");
455 std::array<double, 6> affine_transform;
456 affine_transform[0] = lon_min;
457 affine_transform[1] = 1.0 / lon_bin_scale;
458 affine_transform[2] = 0.0;
459 affine_transform[4] = 0.0;
461 affine_transform[3] = lat_min + (double(raster_height) / lat_bin_scale);
462 affine_transform[5] = -1.0 / lat_bin_scale;
464 affine_transform[3] = lat_min;
465 affine_transform[5] = 1.0 / lat_bin_scale;
469 return tf_raster_contour_impl<TV, TG>(mgr,
472 affine_transform.data(),
473 geo_raster->z_.data(),
484 template <
typename TLL,
typename TV,
typename TG>
489 const int32_t raster_width,
490 const int32_t raster_height,
491 const bool flip_latitude,
492 const TV contour_interval,
493 const TV contour_offset,
499 CHECK_GT(contour_interval, static_cast<TV>(0));
502 auto const num_pixels =
503 static_cast<int64_t
>(raster_width) * static_cast<int64_t>(raster_height);
504 if (lon.
size() != num_pixels || lat.
size() != num_pixels ||
505 values.
size() != num_pixels) {
506 return mgr.ERROR_MESSAGE(
"Raster lon/lat/values size mismatch");
510 double lon_min = double(*std::min_element(lon.
getPtr(), lon.
getPtr() + num_pixels));
511 double lon_max = double(*std::max_element(lon.
getPtr(), lon.
getPtr() + num_pixels));
512 double lat_min = double(*std::min_element(lat.
getPtr(), lat.
getPtr() + num_pixels));
513 double lat_max = double(*std::max_element(lat.
getPtr(), lat.
getPtr() + num_pixels));
517 std::array<double, 6> affine_transform;
518 affine_transform[0] = lon_min;
519 affine_transform[1] = (lon_max - lon_min) /
double(raster_width - 1);
520 affine_transform[2] = 0.0;
521 affine_transform[4] = 0.0;
523 affine_transform[3] = lat_max;
524 affine_transform[5] = (lat_min - lat_max) /
double(raster_height - 1);
526 affine_transform[3] = lat_min;
527 affine_transform[5] = (lat_max - lat_min) /
double(raster_height - 1);
531 return tf_raster_contour_impl<TV, TG>(mgr,
534 affine_transform.data(),
560 template <
typename TLL,
typename TV>
567 const float bin_dim_meters,
568 const int32_t neighborhood_fill_radius,
569 const bool fill_only_nulls,
571 const bool flip_latitude,
572 const TV contour_interval,
573 const TV contour_offset,
576 return GDALTableFunctions::tf_raster_contour_rasterize_impl<TLL, TV, GeoLineString>(
583 neighborhood_fill_radius,
604 template <
typename TLL,
typename TV>
610 const int32_t raster_width,
611 const int32_t raster_height,
612 const bool flip_latitude,
613 const TV contour_interval,
614 const TV contour_offset,
617 return GDALTableFunctions::tf_raster_contour_direct_impl<TLL, TV, GeoLineString>(
643 template <
typename TLL,
typename TV>
650 const float bin_dim_meters,
651 const int32_t neighborhood_fill_radius,
652 const bool fill_only_nulls,
654 const bool flip_latitude,
655 const TV contour_interval,
656 const TV contour_offset,
659 return GDALTableFunctions::tf_raster_contour_rasterize_impl<TLL, TV, GeoPolygon>(
666 neighborhood_fill_radius,
687 template <
typename TLL,
typename TV>
693 const int32_t raster_width,
694 const int32_t raster_height,
695 const bool flip_latitude,
696 const TV contour_interval,
697 const TV contour_offset,
700 return GDALTableFunctions::tf_raster_contour_direct_impl<TLL, TV, GeoPolygon>(
void set_output_row_size(int64_t num_rows)
TEMPLATE_NOINLINE int32_t tf_raster_contour_polygons__cpu_template(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TV > &values, const TextEncodingNone &agg_type, const float bin_dim_meters, const int32_t neighborhood_fill_radius, const bool fill_only_nulls, const TextEncodingNone &fill_agg_type, const bool flip_latitude, const TV contour_interval, const TV contour_offset, Column< GeoPolygon > &contour_polygons, Column< TV > &contour_values)
void set_output_array_values_total_number(int32_t index, int64_t output_array_values_total_number)
std::string getString() const
DEVICE int64_t size() const
DEVICE T * getPtr() const
RasterAggType get_raster_agg_type(const std::string &agg_type_str, const bool is_fill_agg)
std::unique_ptr< OGRFeature, FeatureDeleter > FeatureUqPtr
int32_t tf_raster_contour_rasterize_impl(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TV > &values, const TextEncodingNone &agg_type, const float bin_dim_meters, const int32_t neighborhood_fill_radius, const bool fill_only_nulls, const TextEncodingNone &fill_agg_type, const bool flip_latitude, const TV contour_interval, const TV contour_offset, Column< TG > &contour_features, Column< TV > &contour_values)
std::string toString(const Executor::ExtModuleKinds &kind)
torch::Tensor f(torch::Tensor x, torch::Tensor W_target, torch::Tensor b_target)
TEMPLATE_NOINLINE int32_t tf_raster_contour_lines__cpu_template(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TV > &values, const TextEncodingNone &agg_type, const float bin_dim_meters, const int32_t neighborhood_fill_radius, const bool fill_only_nulls, const TextEncodingNone &fill_agg_type, const bool flip_latitude, const TV contour_interval, const TV contour_offset, Column< GeoLineString > &contour_lines, Column< TV > &contour_values)
int32_t tf_raster_contour_impl(TableFunctionManager &mgr, const int32_t raster_width, const int32_t raster_height, const double affine_transform[6], const TV *values, const TV contour_interval, const TV contour_offset, Column< TG > &contour_features, Column< TV > &contour_values)
int32_t tf_raster_contour_direct_impl(TableFunctionManager &mgr, const Column< TLL > &lon, const Column< TLL > &lat, const Column< TV > &values, const int32_t raster_width, const int32_t raster_height, const bool flip_latitude, const TV contour_interval, const TV contour_offset, Column< TG > &contour_features, Column< TV > &contour_values)
#define TEMPLATE_NOINLINE