2
/****************************************************************
6
* AUTHOR(S): Markus Metz
9
* PURPOSE: Import LiDAR LAS points
11
* COPYRIGHT: (C) 2011-2014 by the GRASS Development Team
13
* This program is free software under the
14
* GNU General Public License (>=v2).
15
* Read the file COPYING that comes with GRASS
18
* TODO: - make fixed field length of OFTIntegerList dynamic
19
* - several other TODOs below
20
**************************************************************/
25
#include <grass/gis.h>
26
#include <grass/dbmi.h>
27
#include <grass/vector.h>
28
#include <grass/gprojects.h>
29
#include <grass/glocale.h>
30
#include <liblas/capi/liblas.h>
33
# define MIN(a,b) ((a<b) ? a : b)
34
# define MAX(a,b) ((a>b) ? a : b)
43
* ASPRS Standard LIDAR Point Classes
44
* Classification Value (bits 0:4) : Meaning
45
* 0 : Created, never classified
49
* 4 : Medium Vegetation
52
* 7 : Low Point (noise)
53
* 8 : Model Key-point (mass point)
55
* 10 : Reserved for ASPRS Definition
56
* 11 : Reserved for ASPRS Definition
58
* 13-31 : Reserved for ASPRS Definition
61
/* Classification Bit Field Encoding
62
* Bits | Field Name | Description
63
* 0-4 | Classification | Standard ASPRS classification as defined in the
64
* above classification table.
65
* 5 | Synthetic | If set then this point was created by a technique
66
* other than LIDAR collection such as digitized from
67
* a photogrammetric stereo model or by traversing
69
* 6 | Key-point | If set, this point is considered to be a model
70
* key-point and thus generally should not be withheld
71
* in a thinning algorithm.
72
* 7 | Withheld | If set, this point should not be included in
73
* processing (synonymous with Deleted).
82
static struct class_table class_val[] = {
83
{0, "Created, never classified"},
86
{3, "Low Vegetation"},
87
{4, "Medium Vegetation"},
88
{5, "High Vegetation"},
90
{7, "Low Point (noise)"},
91
{8, "Model Key-point (mass point)"},
93
{10, "Reserved for ASPRS Definition"},
94
{11, "Reserved for ASPRS Definition"},
95
{12, "Overlap Points"},
96
{13 /* 13 - 31 */, "Reserved for ASPRS Definition"},
100
static struct class_table class_type[] = {
107
void print_lasinfo(LASHeaderH LAS_header, LASSRSH LAS_srs);
109
int main(int argc, char *argv[])
112
float xmin = 0., ymin = 0., xmax = 0., ymax = 0.;
113
struct GModule *module;
114
struct Option *in_opt, *out_opt, *spat_opt, *filter_opt, *class_opt;
115
struct Option *outloc_opt;
116
struct Flag *print_flag, *notab_flag, *region_flag, *notopo_flag;
117
struct Flag *over_flag, *extend_flag, *no_import_flag;
119
struct Key_Value *loc_proj_info = NULL, *loc_proj_units = NULL;
120
struct Key_Value *proj_info, *proj_units;
122
struct Cell_head cellhd, loc_wind, cur_wind;
123
char error_msg[8192];
130
struct field_info *Fi;
132
dbString sql, strval;
135
LASReaderH LAS_reader;
136
LASHeaderH LAS_header;
139
double scale_x, scale_y, scale_z, offset_x, offset_y, offset_z;
140
int las_point_format;
141
int have_time, have_color;
145
unsigned int not_valid;
147
struct line_pnts *Points;
148
struct line_cats *Cats;
150
unsigned int n_features, feature_count, n_outside, n_filtered, n_class_filtered;
155
module = G_define_module();
156
G_add_keyword(_("vector"));
157
G_add_keyword(_("import"));
158
G_add_keyword(_("LIDAR"));
159
module->description = _("Converts LAS LiDAR point clouds to a GRASS vector map with libLAS.");
161
in_opt = G_define_standard_option(G_OPT_F_INPUT);
162
in_opt->label = _("LAS input file");
163
in_opt->description = _("LiDAR input files in LAS format (*.las or *.laz)");
165
out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
167
spat_opt = G_define_option();
168
spat_opt->key = "spatial";
169
spat_opt->type = TYPE_DOUBLE;
170
spat_opt->multiple = YES;
171
spat_opt->required = NO;
172
spat_opt->key_desc = "xmin,ymin,xmax,ymax";
173
spat_opt->label = _("Import subregion only");
174
spat_opt->guisection = _("Subregion");
175
spat_opt->description =
176
_("Format: xmin,ymin,xmax,ymax - usually W,S,E,N");
178
outloc_opt = G_define_option();
179
outloc_opt->key = "location";
180
outloc_opt->type = TYPE_STRING;
181
outloc_opt->required = NO;
182
outloc_opt->description = _("Name for new location to create");
183
outloc_opt->key_desc = "name";
185
filter_opt = G_define_option();
186
filter_opt->key = "return_filter";
187
filter_opt->type = TYPE_STRING;
188
filter_opt->required = NO;
189
filter_opt->label = _("Only import points of selected return type");
190
filter_opt->description = _("If not specified, all points are imported");
191
filter_opt->options = "first,last,mid";
193
class_opt = G_define_option();
194
class_opt->key = "class_filter";
195
class_opt->type = TYPE_INTEGER;
196
class_opt->multiple = YES;
197
class_opt->required = NO;
198
class_opt->label = _("Only import points of selected class(es)");
199
class_opt->description = _("Input is comma separated integers. "
200
"If not specified, all points are imported.");
202
print_flag = G_define_flag();
203
print_flag->key = 'p';
204
print_flag->description =
205
_("Print LAS file info and exit");
206
print_flag->suppress_required = YES;
208
notab_flag = G_define_standard_flag(G_FLG_V_TABLE);
209
notab_flag->guisection = _("Attributes");
211
over_flag = G_define_flag();
212
over_flag->key = 'o';
213
over_flag->description =
214
_("Override dataset projection (use location's projection)");
216
region_flag = G_define_flag();
217
region_flag->key = 'r';
218
region_flag->guisection = _("Subregion");
219
region_flag->description = _("Limit import to the current region");
221
extend_flag = G_define_flag();
222
extend_flag->key = 'e';
223
extend_flag->description =
224
_("Extend region extents based on new dataset");
226
no_import_flag = G_define_flag();
227
no_import_flag->key = 'i';
228
no_import_flag->description =
229
_("Create the location specified by the \"location\" parameter and exit."
230
" Do not import the vector data.");
231
no_import_flag->suppress_required = YES;
233
notopo_flag = G_define_standard_flag(G_FLG_V_TOPO);
235
/* The parser checks if the map already exists in current mapset, this is
236
* wrong if location options is used, so we switch out the check and do it
237
* in the module after the parser */
238
overwrite = G_check_overwrite(argc, argv);
240
if (G_parser(argc, argv))
243
/* Don't crash on cmd line if file not found */
244
if (access(in_opt->answer, F_OK) != 0) {
245
G_fatal_error(_("Input file <%s> does not exist"), in_opt->answer);
248
LAS_reader = LASReader_Create(in_opt->answer);
249
LAS_header = LASReader_GetHeader(LAS_reader);
251
if (LAS_header == NULL) {
252
G_fatal_error(_("Input file <%s> is not a LAS LiDAR point cloud"),
256
LAS_srs = LASHeader_GetSRS(LAS_header);
258
scale_x = LASHeader_GetScaleX(LAS_header);
259
scale_y = LASHeader_GetScaleY(LAS_header);
260
scale_z = LASHeader_GetScaleZ(LAS_header);
262
offset_x = LASHeader_GetOffsetX(LAS_header);
263
offset_y = LASHeader_GetOffsetY(LAS_header);
264
offset_z = LASHeader_GetOffsetZ(LAS_header);
266
xmin = LASHeader_GetMinX(LAS_header);
267
xmax = LASHeader_GetMaxX(LAS_header);
268
ymin = LASHeader_GetMinY(LAS_header);
269
ymax = LASHeader_GetMaxY(LAS_header);
271
/* Print LAS header */
272
if (print_flag->answer) {
274
print_lasinfo(LAS_header, LAS_srs);
276
LASSRS_Destroy(LAS_srs);
277
LASHeader_Destroy(LAS_header);
278
LASReader_Destroy(LAS_reader);
283
return_filter = LAS_ALL;
284
if (filter_opt->answer) {
285
if (strcmp(filter_opt->answer, "first") == 0)
286
return_filter = LAS_FIRST;
287
else if (strcmp(filter_opt->answer, "last") == 0)
288
return_filter = LAS_LAST;
289
else if (strcmp(filter_opt->answer, "mid") == 0)
290
return_filter = LAS_MID;
292
G_fatal_error(_("Unknown filter option <%s>"), filter_opt->answer);
295
if (region_flag->answer) {
296
if (spat_opt->answer)
297
G_fatal_error(_("Select either the current region flag or the spatial option, not both"));
299
G_get_window(&cur_wind);
300
xmin = cur_wind.west;
301
xmax = cur_wind.east;
302
ymin = cur_wind.south;
303
ymax = cur_wind.north;
305
if (spat_opt->answer) {
306
/* See as reference: gdal/ogr/ogr_capi_test.c */
308
/* cut out a piece of the map */
309
/* order: xmin,ymin,xmax,ymax */
312
while (spat_opt->answers[i]) {
314
xmin = atof(spat_opt->answers[i]);
316
ymin = atof(spat_opt->answers[i]);
318
xmax = atof(spat_opt->answers[i]);
320
ymax = atof(spat_opt->answers[i]);
325
G_fatal_error(_("4 parameters required for 'spatial' parameter"));
327
if (spat_opt->answer || region_flag->answer) {
328
G_debug(2, "cut out with boundaries: xmin:%f ymin:%f xmax:%f ymax:%f",
329
xmin, ymin, xmax, ymax);
332
/* fetch boundaries */
333
G_get_window(&cellhd);
338
cellhd.rows = 20; /* TODO - calculate useful values */
340
cellhd.ns_res = (cellhd.north - cellhd.south) / cellhd.rows;
341
cellhd.ew_res = (cellhd.east - cellhd.west) / cellhd.cols;
343
/* Fetch input map projection in GRASS form. */
346
projstr = LASSRS_GetWKT_CompoundOK(LAS_srs);
348
/* Do we need to create a new location? */
349
if (outloc_opt->answer != NULL) {
350
/* Convert projection information non-interactively as we can't
351
* assume the user has a terminal open */
352
if (GPJ_wkt_to_grass(&cellhd, &proj_info,
353
&proj_units, projstr, 0) < 0) {
354
G_fatal_error(_("Unable to convert input map projection to GRASS "
355
"format; cannot create new location."));
358
if (0 != G_make_location(outloc_opt->answer, &cellhd,
359
proj_info, proj_units)) {
360
G_fatal_error(_("Unable to create new location <%s>"),
363
G_message(_("Location <%s> created"), outloc_opt->answer);
366
/* If the i flag is set, clean up? and exit here */
367
if(no_import_flag->answer)
371
G_warning("Import into new location not yet implemented");
372
/* at this point the module should be using G_create_alt_env()
373
to change context to the newly created location; once done
374
it should switch back with G_switch_env(). See r.in.gdal */
379
/* Projection only required for checking so convert non-interactively */
380
if (GPJ_wkt_to_grass(&cellhd, &proj_info,
381
&proj_units, projstr, 0) < 0)
382
G_warning(_("Unable to convert input map projection information to "
383
"GRASS format for checking"));
385
/* Does the projection of the current location match the dataset? */
386
/* G_get_window seems to be unreliable if the location has been changed */
387
G_get_default_window(&loc_wind);
388
/* fetch LOCATION PROJ info */
389
if (loc_wind.proj != PROJECTION_XY) {
390
loc_proj_info = G_get_projinfo();
391
loc_proj_units = G_get_projunits();
394
if (over_flag->answer) {
395
cellhd.proj = loc_wind.proj;
396
cellhd.zone = loc_wind.zone;
397
G_message(_("Over-riding projection check"));
399
else if (loc_wind.proj != cellhd.proj
401
G_compare_projections(loc_proj_info, loc_proj_units,
402
proj_info, proj_units)) != TRUE) {
406
_("Projection of dataset does not"
407
" appear to match current location.\n\n"));
409
/* TODO: output this info sorted by key: */
410
if (loc_wind.proj != cellhd.proj || err != -2) {
411
if (loc_proj_info != NULL) {
412
strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n"));
413
for (i_value = 0; i_value < loc_proj_info->nitems;
415
sprintf(error_msg + strlen(error_msg), "%s: %s\n",
416
loc_proj_info->key[i_value],
417
loc_proj_info->value[i_value]);
418
strcat(error_msg, "\n");
421
if (proj_info != NULL) {
422
strcat(error_msg, _("Import dataset PROJ_INFO is:\n"));
423
for (i_value = 0; i_value < proj_info->nitems; i_value++)
424
sprintf(error_msg + strlen(error_msg), "%s: %s\n",
425
proj_info->key[i_value],
426
proj_info->value[i_value]);
429
strcat(error_msg, _("Import dataset PROJ_INFO is:\n"));
430
if (cellhd.proj == PROJECTION_XY)
431
sprintf(error_msg + strlen(error_msg),
432
"Dataset proj = %d (unreferenced/unknown)\n",
434
else if (cellhd.proj == PROJECTION_LL)
435
sprintf(error_msg + strlen(error_msg),
436
"Dataset proj = %d (lat/long)\n",
438
else if (cellhd.proj == PROJECTION_UTM)
439
sprintf(error_msg + strlen(error_msg),
440
"Dataset proj = %d (UTM), zone = %d\n",
441
cellhd.proj, cellhd.zone);
443
sprintf(error_msg + strlen(error_msg),
444
"Dataset proj = %d (unknown), zone = %d\n",
445
cellhd.proj, cellhd.zone);
449
if (loc_proj_units != NULL) {
450
strcat(error_msg, "GRASS LOCATION PROJ_UNITS is:\n");
451
for (i_value = 0; i_value < loc_proj_units->nitems;
453
sprintf(error_msg + strlen(error_msg), "%s: %s\n",
454
loc_proj_units->key[i_value],
455
loc_proj_units->value[i_value]);
456
strcat(error_msg, "\n");
459
if (proj_units != NULL) {
460
strcat(error_msg, "Import dataset PROJ_UNITS is:\n");
461
for (i_value = 0; i_value < proj_units->nitems; i_value++)
462
sprintf(error_msg + strlen(error_msg), "%s: %s\n",
463
proj_units->key[i_value],
464
proj_units->value[i_value]);
467
sprintf(error_msg + strlen(error_msg),
468
_("\nYou can use the -o flag to %s to override this projection check.\n"),
471
_("Consider generating a new location with 'location' parameter"
472
" from input data set.\n"));
473
G_fatal_error(error_msg);
476
G_verbose_message(_("Projection of input dataset and current "
477
"location appear to match"));
481
db_init_string(&sql);
482
db_init_string(&strval);
484
if (!outloc_opt->answer) { /* Check if the map exists */
485
if (G_find_vector2(out_opt->answer, G_mapset())) {
487
G_warning(_("Vector map <%s> already exists and will be overwritten"),
490
G_fatal_error(_("Vector map <%s> already exists"),
495
/* open output vector */
496
sprintf(buf, "%s", out_opt->answer);
497
/* strip any @mapset from vector output name */
498
G_find_vector(buf, G_mapset());
499
if (Vect_open_new(&Map, out_opt->answer, 1) < 0)
500
G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
502
Vect_hist_command(&Map);
504
n_features = LASHeader_GetPointRecordsCount(LAS_header);
505
las_point_format = LASHeader_GetDataFormatId(LAS_header);
507
have_time = (las_point_format == 1 || las_point_format == 3 ||
508
las_point_format == 4 || las_point_format == 5);
510
have_color = (las_point_format == 2 || las_point_format == 3 ||
511
las_point_format == 5);
514
if (!notab_flag->answer) {
515
char *cat_col_name = GV_KEY_COLUMN;
517
Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE);
519
Vect_map_add_dblink(&Map, 1, out_opt->answer, Fi->table,
520
cat_col_name, Fi->database, Fi->driver);
522
/* check available LAS info, depends on POINT DATA RECORD FORMAT [0-5] */
526
* intensity (double),
527
* return number (int),
528
* number of returns (int),
529
* scan direction (int),
530
* flight line edge (int),
531
* classification type (char),
533
* time (double) (FORMAT 1, 3, 4, 5),
534
* scan angle rank (int),
536
* user data (char), ???
537
* red (int) (FORMAT 2, 3, 5),
538
* green (int) (FORMAT 2, 3, 5),
539
* blue (int) (FORMAT 2, 3, 5)*/
542
sprintf(buf, "create table %s (%s integer", Fi->table,
544
db_set_string(&sql, buf);
547
sprintf(buf, ", x_coord double precision");
548
db_append_string(&sql, buf);
549
sprintf(buf, ", y_coord double precision");
550
db_append_string(&sql, buf);
551
sprintf(buf, ", z_coord double precision");
552
db_append_string(&sql, buf);
554
sprintf(buf, ", intensity integer");
555
db_append_string(&sql, buf);
557
sprintf(buf, ", return integer");
558
db_append_string(&sql, buf);
559
/* number of returns */
560
sprintf(buf, ", n_returns integer");
561
db_append_string(&sql, buf);
563
sprintf(buf, ", scan_dir integer");
564
db_append_string(&sql, buf);
565
/* flight line edge */
566
sprintf(buf, ", edge integer");
567
db_append_string(&sql, buf);
568
/* classification type */
569
sprintf(buf, ", cl_type varchar(20)");
570
db_append_string(&sql, buf);
571
/* classification class */
572
sprintf(buf, ", class varchar(40)");
573
db_append_string(&sql, buf);
576
sprintf(buf, ", gps_time double precision");
577
db_append_string(&sql, buf);
580
sprintf(buf, ", angle integer");
581
db_append_string(&sql, buf);
583
sprintf(buf, ", src_id integer");
584
db_append_string(&sql, buf);
586
sprintf(buf, ", usr_data integer");
587
db_append_string(&sql, buf);
590
sprintf(buf, ", red integer, green integer, blue integer");
591
db_append_string(&sql, buf);
592
sprintf(buf, ", GRASSRGB varchar(11)");
593
db_append_string(&sql, buf);
596
db_append_string(&sql, ")");
597
G_debug(3, db_get_string(&sql));
600
db_start_driver_open_database(Fi->driver,
601
Vect_subst_var(Fi->database,
603
if (driver == NULL) {
604
G_fatal_error(_("Unable open database <%s> by driver <%s>"),
605
Vect_subst_var(Fi->database, &Map), Fi->driver);
607
db_set_error_handler_driver(driver);
609
if (db_execute_immediate(driver, &sql) != DB_OK) {
610
G_fatal_error(_("Unable to create table: '%s'"),
611
db_get_string(&sql));
614
if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK)
615
G_warning(_("Unable to create index for table <%s>, key <%s>"),
616
Fi->table, cat_col_name);
618
if (db_grant_on_table
619
(driver, Fi->table, DB_PRIV_SELECT,
620
DB_GROUP | DB_PUBLIC) != DB_OK)
621
G_fatal_error(_("Unable to grant privileges on table <%s>"),
624
db_begin_transaction(driver);
633
n_class_filtered = 0;
635
Points = Vect_new_line_struct();
636
Cats = Vect_new_cats_struct();
638
G_important_message(_("Scanning %d points..."), n_features);
639
while ((LAS_point = LASReader_GetNextPoint(LAS_reader)) != NULL) {
642
G_percent(feature_count++, n_features, 1); /* show something happens */
644
if (!LASPoint_IsValid(LAS_point)) {
649
Vect_reset_line(Points);
650
Vect_reset_cats(Cats);
652
x = LASPoint_GetX(LAS_point);
653
y = LASPoint_GetY(LAS_point);
654
z = LASPoint_GetZ(LAS_point);
656
if (spat_opt->answer || region_flag->answer) {
657
if (x < xmin || x > xmax || y < ymin || y > ymax) {
662
if (return_filter != LAS_ALL) {
663
int return_no = LASPoint_GetReturnNumber(LAS_point);
664
int n_returns = LASPoint_GetNumberOfReturns(LAS_point);
667
switch (return_filter) {
673
if (return_no > 1 && return_no < n_returns)
677
if (n_returns > 1 && return_no == n_returns)
687
if (class_opt->answer) {
688
point_class = (int) LASPoint_GetClassification(LAS_point);
691
while (class_opt->answers[i]) {
692
if (point_class == atoi(class_opt->answers[i])) {
704
Vect_append_point(Points, x, y, z);
705
Vect_cat_set(Cats, 1, cat);
706
Vect_write_line(&Map, GV_POINT, Points, Cats);
709
if (!notab_flag->answer) {
711
int las_class_type, las_class;
713
/* use LASPoint_Validate (LASPointH hPoint) to check for
714
* return number, number of returns, scan direction, flight line edge,
715
* classification, scan angle rank */
716
sprintf(buf, "insert into %s values ( %d", Fi->table, cat);
717
db_set_string(&sql, buf);
720
sprintf(buf, ", %f", x);
721
db_append_string(&sql, buf);
722
sprintf(buf, ", %f", y);
723
db_append_string(&sql, buf);
724
sprintf(buf, ", %f", z);
725
db_append_string(&sql, buf);
727
sprintf(buf, ", %d", LASPoint_GetIntensity(LAS_point));
728
db_append_string(&sql, buf);
730
sprintf(buf, ", %d", LASPoint_GetReturnNumber(LAS_point));
731
db_append_string(&sql, buf);
732
/* number of returns */
733
sprintf(buf, ", %d", LASPoint_GetNumberOfReturns(LAS_point));
734
db_append_string(&sql, buf);
736
sprintf(buf, ", %d", LASPoint_GetScanDirection(LAS_point));
737
db_append_string(&sql, buf);
738
/* flight line edge */
739
sprintf(buf, ", %d", LASPoint_GetFlightLineEdge(LAS_point));
740
db_append_string(&sql, buf);
741
class_flag = LASPoint_GetClassification(LAS_point);
742
/* classification type int or char ? */
743
las_class_type = class_flag / 32;
744
sprintf(buf, ", \"%s\"", class_type[las_class_type].name);
745
db_append_string(&sql, buf);
746
/* classification class int or char ? */
747
las_class = class_flag % 32;
750
sprintf(buf, ", \"%s\"", class_val[las_class].name);
751
db_append_string(&sql, buf);
754
sprintf(buf, ", %f", LASPoint_GetTime(LAS_point));
755
db_append_string(&sql, buf);
758
sprintf(buf, ", %d", LASPoint_GetScanAngleRank(LAS_point));
759
db_append_string(&sql, buf);
761
sprintf(buf, ", %d", LASPoint_GetPointSourceId(LAS_point));
762
db_append_string(&sql, buf);
764
sprintf(buf, ", %d", LASPoint_GetUserData(LAS_point));
765
db_append_string(&sql, buf);
768
LASColorH LAS_color = LASPoint_GetColor(LAS_point);
769
int red = LASColor_GetRed(LAS_color);
770
int green = LASColor_GetGreen(LAS_color);
771
int blue = LASColor_GetBlue(LAS_color);
773
sprintf(buf, ", %d, %d, %d", red, green, blue);
774
db_append_string(&sql, buf);
775
sprintf(buf, ", \"%03d:%03d:%03d\"", red, green, blue);
776
db_append_string(&sql, buf);
778
db_append_string(&sql, " )");
779
G_debug(3, db_get_string(&sql));
781
if (db_execute_immediate(driver, &sql) != DB_OK) {
782
G_fatal_error(_("Cannot insert new row: %s"),
783
db_get_string(&sql));
789
G_percent(n_features, n_features, 1); /* finish it */
791
if (!notab_flag->answer) {
792
db_commit_transaction(driver);
793
db_close_database_shutdown_driver(driver);
796
LASSRS_Destroy(LAS_srs);
797
LASHeader_Destroy(LAS_header);
798
LASReader_Destroy(LAS_reader);
801
if (!notopo_flag->answer)
805
G_message(_("%d points imported"),
806
n_features - not_valid - n_outside - n_filtered - n_class_filtered);
808
G_message(_("%d input points were not valid"), not_valid);
810
G_message(_("%d input points were outside of the selected area"), n_outside);
812
G_message(_("%d input points were filtered out by return number"), n_filtered);
813
if (n_class_filtered)
814
G_message(_("%d input points were filtered out by class number"), n_class_filtered);
816
/* -------------------------------------------------------------------- */
817
/* Extend current window based on dataset. */
818
/* -------------------------------------------------------------------- */
819
if (extend_flag->answer) {
820
G_get_set_window(&loc_wind);
822
loc_wind.north = MAX(loc_wind.north, cellhd.north);
823
loc_wind.south = MIN(loc_wind.south, cellhd.south);
824
loc_wind.west = MIN(loc_wind.west, cellhd.west);
825
loc_wind.east = MAX(loc_wind.east, cellhd.east);
827
loc_wind.rows = (int)ceil((loc_wind.north - loc_wind.south)
829
loc_wind.south = loc_wind.north - loc_wind.rows * loc_wind.ns_res;
831
loc_wind.cols = (int)ceil((loc_wind.east - loc_wind.west)
833
loc_wind.east = loc_wind.west + loc_wind.cols * loc_wind.ew_res;
835
G_put_window(&loc_wind);
841
void print_lasinfo(LASHeaderH LAS_header, LASSRSH LAS_srs)
843
char *las_srs_proj4 = LASSRS_GetProj4(LAS_srs);
844
int las_point_format = LASHeader_GetDataFormatId(LAS_header);
846
fprintf(stdout, "\nUsing LAS Library Version '%s'\n\n",
847
LAS_GetFullVersion());
848
fprintf(stdout, "LAS File Version: %d.%d\n",
849
LASHeader_GetVersionMajor(LAS_header),
850
LASHeader_GetVersionMinor(LAS_header));
851
fprintf(stdout, "System ID: '%s'\n",
852
LASHeader_GetSystemId(LAS_header));
853
fprintf(stdout, "Generating Software: '%s'\n",
854
LASHeader_GetSoftwareId(LAS_header));
855
fprintf(stdout, "File Creation Day/Year: %d/%d\n",
856
LASHeader_GetCreationDOY(LAS_header),
857
LASHeader_GetCreationYear(LAS_header));
858
fprintf(stdout, "Point Data Format: %d\n",
860
fprintf(stdout, "Number of Point Records: %d\n",
861
LASHeader_GetPointRecordsCount(LAS_header));
862
fprintf(stdout, "Number of Points by Return: %d %d %d %d %d\n",
863
LASHeader_GetPointRecordsByReturnCount(LAS_header, 0),
864
LASHeader_GetPointRecordsByReturnCount(LAS_header, 1),
865
LASHeader_GetPointRecordsByReturnCount(LAS_header, 2),
866
LASHeader_GetPointRecordsByReturnCount(LAS_header, 3),
867
LASHeader_GetPointRecordsByReturnCount(LAS_header, 4));
868
fprintf(stdout, "Scale Factor X Y Z: %g %g %g\n",
869
LASHeader_GetScaleX(LAS_header),
870
LASHeader_GetScaleY(LAS_header),
871
LASHeader_GetScaleZ(LAS_header));
872
fprintf(stdout, "Offset X Y Z: %g %g %g\n",
873
LASHeader_GetOffsetX(LAS_header),
874
LASHeader_GetOffsetY(LAS_header),
875
LASHeader_GetOffsetZ(LAS_header));
876
fprintf(stdout, "Min X Y Z: %g %g %g\n",
877
LASHeader_GetMinX(LAS_header),
878
LASHeader_GetMinY(LAS_header),
879
LASHeader_GetMinZ(LAS_header));
880
fprintf(stdout, "Max X Y Z: %g %g %g\n",
881
LASHeader_GetMaxX(LAS_header),
882
LASHeader_GetMaxY(LAS_header),
883
LASHeader_GetMaxZ(LAS_header));
884
if (las_srs_proj4 && strlen(las_srs_proj4) > 0) {
885
fprintf(stdout, "Spatial Reference:\n");
886
fprintf(stdout, "%s\n", las_srs_proj4);
889
fprintf(stdout, "Spatial Reference: None\n");
892
fprintf(stdout, "\nData Fields:\n");
893
fprintf(stdout, " 'X'\n 'Y'\n 'Z'\n 'Intensity'\n 'Return Number'\n");
894
fprintf(stdout, " 'Number of Returns'\n 'Scan Direction'\n");
895
fprintf(stdout, " 'Flighline Edge'\n 'Classification'\n 'Scan Angle Rank'\n");
896
fprintf(stdout, " 'User Data'\n 'Point Source ID'\n");
897
if (las_point_format == 1 || las_point_format == 3 || las_point_format == 4 || las_point_format == 5) {
898
fprintf(stdout, " 'GPS Time'\n");
900
if (las_point_format == 2 || las_point_format == 3 || las_point_format == 5) {
901
fprintf(stdout, " 'Red'\n 'Green'\n 'Blue'\n");
903
fprintf(stdout, "\n");