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;
void set_output_row_size(int64_t num_rows)
void set_output_array_values_total_number(int32_t index, int64_t output_array_values_total_number)
std::unique_ptr< OGRFeature, FeatureDeleter > FeatureUqPtr
std::string toString(const Executor::ExtModuleKinds &kind)