@@ -19,10 +19,19 @@ use std::io::{Error, ErrorKind};
1919use std:: path;
2020
2121/// Creates a raster grid based on a triangular irregular network (TIN) fitted to vector points
22- /// and linear interpolation within each triangular-shaped plane.
22+ /// and linear interpolation within each triangular-shaped plane. The TIN creation algorithm is based on
23+ /// [Delaunay triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation).
2324///
25+ /// The user must specify the attribute field containing point values (`--field`). Alternatively, if the input Shapefile
26+ /// contains z-values, the interpolation may be based on these values (`--use_z`). Either an output grid resolution
27+ /// (`--cell_size`) must be specified or alternatively an existing base file (`--base`) can be used to determine the
28+ /// output raster's (`--output`) resolution and spatial extent. Natural neighbour interpolation generally produces a
29+ /// satisfactorily smooth surface within the region of data points but can produce spurious breaks in the surface
30+ /// outside of this region. Thus, it is recommended that the output surface be clipped to the convex hull of the input
31+ /// points (`--clip`).
32+ ///
2433/// # See Also
25- /// `LidarTINGridding`, `ConstructVectorTIN`
34+ /// `LidarTINGridding`, `ConstructVectorTIN`, `NaturalNeighbourInterpolation`
2635pub struct TINGridding {
2736 name : String ,
2837 description : String ,
@@ -90,7 +99,16 @@ impl TINGridding {
9099 description : "Output raster's grid resolution." . to_owned ( ) ,
91100 parameter_type : ParameterType :: Float ,
92101 default_value : None ,
93- optional : false ,
102+ optional : true ,
103+ } ) ;
104+
105+ parameters. push ( ToolParameter {
106+ name : "Base Raster File (optional)" . to_owned ( ) ,
107+ flags : vec ! [ "--base" . to_owned( ) ] ,
108+ description : "Optionally specified input base raster file. Not used when a cell size is specified." . to_owned ( ) ,
109+ parameter_type : ParameterType :: ExistingFile ( ParameterFileType :: Raster ) ,
110+ default_value : None ,
111+ optional : true
94112 } ) ;
95113
96114 parameters. push ( ToolParameter {
@@ -175,7 +193,8 @@ impl WhiteboxTool for TINGridding {
175193 let mut use_z = false ;
176194 let mut use_field = false ;
177195 let mut output_file: String = "" . to_string ( ) ;
178- let mut grid_res: f64 = 1.0 ;
196+ let mut grid_res: f64 = 0.0 ;
197+ let mut base_file = String :: new ( ) ;
179198 let mut max_triangle_edge_length = f64:: INFINITY ;
180199
181200 // read the arguments
@@ -232,6 +251,12 @@ impl WhiteboxTool for TINGridding {
232251 } ;
233252
234253 max_triangle_edge_length *= max_triangle_edge_length; // actually squared distance
254+ } else if flag_val == "-base" {
255+ base_file = if keyval {
256+ vec[ 1 ] . to_string ( )
257+ } else {
258+ args[ i + 1 ] . to_string ( )
259+ } ;
235260 }
236261 }
237262
@@ -300,30 +325,81 @@ impl WhiteboxTool for TINGridding {
300325 }
301326 }
302327
303- let west: f64 = input. header . x_min ;
304- let north: f64 = input. header . y_max ;
305- let rows: isize = ( ( ( north - input. header . y_min ) / grid_res) . ceil ( ) ) as isize ;
306- let columns: isize = ( ( ( input. header . x_max - west) / grid_res) . ceil ( ) ) as isize ;
307- let south: f64 = north - rows as f64 * grid_res;
308- let east = west + columns as f64 * grid_res;
309- let nodata = -32768.0f64 ;
328+ // let west: f64 = input.header.x_min;
329+ // let north: f64 = input.header.y_max;
330+ // let rows: isize = (((north - input.header.y_min) / grid_res).ceil()) as isize;
331+ // let columns: isize = (((input.header.x_max - west) / grid_res).ceil()) as isize;
332+ // let south: f64 = north - rows as f64 * grid_res;
333+ // let east = west + columns as f64 * grid_res;
334+ // let nodata = -32768.0f64;
335+
336+ // let mut configs = RasterConfigs {
337+ // ..Default::default()
338+ // };
339+ // configs.rows = rows as usize;
340+ // configs.columns = columns as usize;
341+ // configs.north = north;
342+ // configs.south = south;
343+ // configs.east = east;
344+ // configs.west = west;
345+ // configs.resolution_x = grid_res;
346+ // configs.resolution_y = grid_res;
347+ // configs.nodata = nodata;
348+ // configs.data_type = DataType::F32;
349+ // configs.photometric_interp = PhotometricInterpretation::Continuous;
350+
351+ // let mut output = Raster::initialize_using_config(&output_file, &configs);
310352
311- let mut configs = RasterConfigs {
312- ..Default :: default ( )
353+ let nodata = -32768.0f64 ;
354+ let mut output = if !base_file. trim ( ) . is_empty ( ) || grid_res == 0f64 {
355+ if !base_file. contains ( & sep) && !base_file. contains ( "/" ) {
356+ base_file = format ! ( "{}{}" , working_directory, base_file) ;
357+ }
358+ let mut base = Raster :: new ( & base_file, "r" ) ?;
359+ base. configs . nodata = nodata;
360+ Raster :: initialize_using_file ( & output_file, & base)
361+ } else {
362+ if grid_res == 0f64 {
363+ return Err ( Error :: new (
364+ ErrorKind :: InvalidInput ,
365+ "The specified grid resolution is incorrect. Either a non-zero grid resolution \n or an input existing base file name must be used." ,
366+ ) ) ;
367+ }
368+ // base the output raster on the grid_res and the
369+ // extent of the input vector.
370+ let west: f64 = input. header . x_min ;
371+ let north: f64 = input. header . y_max ;
372+ let rows: isize = ( ( ( north - input. header . y_min ) / grid_res) . ceil ( ) ) as isize ;
373+ let columns: isize = ( ( ( input. header . x_max - west) / grid_res) . ceil ( ) ) as isize ;
374+ let south: f64 = north - rows as f64 * grid_res;
375+ let east = west + columns as f64 * grid_res;
376+
377+ let mut configs = RasterConfigs {
378+ ..Default :: default ( )
379+ } ;
380+ configs. rows = rows as usize ;
381+ configs. columns = columns as usize ;
382+ configs. north = north;
383+ configs. south = south;
384+ configs. east = east;
385+ configs. west = west;
386+ configs. resolution_x = grid_res;
387+ configs. resolution_y = grid_res;
388+ configs. nodata = nodata;
389+ configs. data_type = DataType :: F32 ;
390+ configs. photometric_interp = PhotometricInterpretation :: Continuous ;
391+
392+ Raster :: initialize_using_config ( & output_file, & configs)
313393 } ;
314- configs. rows = rows as usize ;
315- configs. columns = columns as usize ;
316- configs. north = north;
317- configs. south = south;
318- configs. east = east;
319- configs. west = west;
320- configs. resolution_x = grid_res;
321- configs. resolution_y = grid_res;
322- configs. nodata = nodata;
323- configs. data_type = DataType :: F32 ;
324- configs. photometric_interp = PhotometricInterpretation :: Continuous ;
325-
326- let mut output = Raster :: initialize_using_config ( & output_file, & configs) ;
394+
395+ let west = output. configs . west ;
396+ let north = output. configs . north ;
397+ output. configs . nodata = nodata; // in case a base image is used with a different nodata value.
398+ output. configs . palette = "spectrum.pal" . to_string ( ) ;
399+ output. configs . data_type = DataType :: F32 ;
400+ output. configs . photometric_interp = PhotometricInterpretation :: Continuous ;
401+ let res_x = output. configs . resolution_x ;
402+ let res_y = output. configs . resolution_y ;
327403
328404 let mut points: Vec < Point2D > = vec ! [ ] ;
329405 let mut z_values: Vec < f64 > = vec ! [ ] ;
@@ -414,15 +490,15 @@ impl WhiteboxTool for TINGridding {
414490 left = points[ p1] . x . min ( points[ p2] . x . min ( points[ p3] . x ) ) ;
415491 right = points[ p1] . x . max ( points[ p2] . x . max ( points[ p3] . x ) ) ;
416492
417- bottom_row = ( ( north - bottom) / grid_res ) . ceil ( ) as isize ;
418- top_row = ( ( north - top) / grid_res ) . floor ( ) as isize ;
419- left_col = ( ( left - west) / grid_res ) . floor ( ) as isize ;
420- right_col = ( ( right - west) / grid_res ) . ceil ( ) as isize ;
493+ bottom_row = ( ( north - bottom) / res_y ) . ceil ( ) as isize ;
494+ top_row = ( ( north - top) / res_y ) . floor ( ) as isize ;
495+ left_col = ( ( left - west) / res_x ) . floor ( ) as isize ;
496+ right_col = ( ( right - west) / res_x ) . ceil ( ) as isize ;
421497
422498 for row in top_row..=bottom_row {
423499 for col in left_col..=right_col {
424- x = west + ( col as f64 + 0.5 ) * grid_res ;
425- y = north - ( row as f64 + 0.5 ) * grid_res ;
500+ x = west + ( col as f64 + 0.5 ) * res_x ;
501+ y = north - ( row as f64 + 0.5 ) * res_y ;
426502 if point_in_poly ( & Point2D :: new ( x, y) , & tri_points) {
427503 // calculate the z values
428504 z = -( norm. x * x + norm. y * y + k) / norm. z ;
0 commit comments