[GRASS-SVN] r66855 - in grass/trunk/vector: . v.out.lidar

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Nov 16 18:34:01 PST 2015


Author: wenzeslaus
Date: 2015-11-16 18:34:01 -0800 (Mon, 16 Nov 2015)
New Revision: 66855

Added:
   grass/trunk/vector/v.out.lidar/
   grass/trunk/vector/v.out.lidar/Makefile
   grass/trunk/vector/v.out.lidar/main.c
   grass/trunk/vector/v.out.lidar/v.out.lidar.html
Modified:
   grass/trunk/vector/Makefile
Log:
v.out.lidar: export vector as LAS

Supports vector color tables (associated with category),
attribute table with GRASS RGB column or individual columns.
It also supports colors stored as category of a feature
(individually or in one number). See
https://lists.osgeo.org/pipermail/grass-dev/2015-September/076552.html

>From other typical lidar attributes, only subset is
currently supported (as both attributes and categories
in individal layers).

Writes meta for the coordinate system taken from GRASS Location info.

Can limit export 2D extent using computatioal region.

Offset and scale for coordinates is not currently supported.
Where and other cases when point must be skipped are not
implemented. Doesn't handle well G_OPT_V_FIELD_ALL.


Modified: grass/trunk/vector/Makefile
===================================================================
--- grass/trunk/vector/Makefile	2015-11-16 22:34:42 UTC (rev 66854)
+++ grass/trunk/vector/Makefile	2015-11-17 02:34:01 UTC (rev 66855)
@@ -57,6 +57,7 @@
 	v.normal \
 	v.out.ascii \
 	v.out.dxf \
+	v.out.lidar \
 	v.out.postgis \
 	v.out.pov \
 	v.out.svg \

Added: grass/trunk/vector/v.out.lidar/Makefile
===================================================================
--- grass/trunk/vector/v.out.lidar/Makefile	                        (rev 0)
+++ grass/trunk/vector/v.out.lidar/Makefile	2015-11-17 02:34:01 UTC (rev 66855)
@@ -0,0 +1,16 @@
+MODULE_TOPDIR = ../..
+
+PGM=v.out.lidar
+
+LIBES = $(GPROJLIB) $(VECTORLIB) $(DBMILIB) $(GISLIB) $(LASLIBS) $(MATHLIB) $(RASTERLIB)
+DEPENDENCIES = $(GPROJDEP) $(VECTORDEP) $(DBMIDEP) $(GISDEP) $(RASTERDEP)
+
+EXTRA_INC = $(VECT_INC) $(PROJINC) $(LASINC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+ifneq ($(USE_LIBLAS),)
+default: cmd
+endif
+


Property changes on: grass/trunk/vector/v.out.lidar/Makefile
___________________________________________________________________
Added: svn:mime-type
   + text/x-makefile
Added: svn:eol-style
   + native

Added: grass/trunk/vector/v.out.lidar/main.c
===================================================================
--- grass/trunk/vector/v.out.lidar/main.c	                        (rev 0)
+++ grass/trunk/vector/v.out.lidar/main.c	2015-11-17 02:34:01 UTC (rev 66855)
@@ -0,0 +1,799 @@
+/***********************************************************************
+ *
+ * MODULE:       v.out.lidar
+ *
+ * AUTHOR(S):    Vaclav Petras
+ *
+ * PURPOSE:      Export LiDAR LAS points
+ *
+ * COPYRIGHT:    (C) 2015 by Vaclav Petras and the GRASS Development Team
+ *
+ *               This program is free software under the
+ *               GNU General Public License (>=v2).
+ *               Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+***********************************************************************/
+
+#include <stdlib.h>
+
+#include <grass/gis.h>
+#include <grass/colors.h>
+#include <grass/raster.h>
+#include <grass/dbmi.h>
+#include <grass/vector.h>
+#include <grass/gprojects.h>
+#include <grass/glocale.h>
+
+#include <liblas/capi/liblas.h>
+
+
+struct WriteContext
+{
+    LASWriterH las_writer;
+    LASPointH las_point;
+    LASColorH las_color;
+    struct Colors *color_table;
+    int layer;
+    int return_layer;
+    int n_returns_layer;
+    int class_layer;
+    int rgb_layer;
+    int red_layer;
+    int green_layer;
+    int blue_layer;
+    dbCatValArray *return_column_values;
+    dbCatValArray *n_returns_column_values;
+    dbCatValArray *class_column_values;
+    dbCatValArray *grass_rgb_column_values;
+    dbCatValArray *red_column_values;
+    dbCatValArray *green_column_values;
+    dbCatValArray *blue_column_values;
+};
+
+
+struct LidarColumnNames
+{
+    const char *return_n;
+    const char *n_returns;
+    const char *class_n;
+    const char *grass_rgb;
+    const char *red;
+    const char *green;
+    const char *blue;
+};
+
+
+/*! Open database and store driver and field info
+ * 
+ * Use close_database() when you are finished with queries
+ */
+static void open_database(struct Map_info *vector, int field,
+                          dbDriver ** driver, struct field_info **f_info)
+{
+    struct field_info *f_info_tmp;
+
+    f_info_tmp = Vect_get_field(vector, field);
+    dbDriver *driver_tmp;
+
+    if (f_info == NULL) {
+        /* not ideal message since we don't know the original name of
+         * the field in case of OGR */
+        G_fatal_error(_("Database connection not defined for layer <%d>"),
+                      field);
+    }
+
+    driver_tmp =
+        db_start_driver_open_database(f_info_tmp->driver,
+                                      f_info_tmp->database);
+    if (driver_tmp == NULL)
+        G_fatal_error("Unable to open database <%s> by driver <%s>",
+                      f_info_tmp->database, f_info_tmp->driver);
+    db_set_error_handler_driver(driver_tmp);
+    *f_info = f_info_tmp;
+    *driver = driver_tmp;
+}
+
+static void close_database(dbDriver * driver)
+{
+    db_close_database_shutdown_driver(driver);
+}
+
+/*! Get values in a column
+ *
+ * Checks the type of the column; fails with fatal for non-numeric columns
+ * and warns for floating point columns.
+ *
+ * Use db_CatValArray_free() and G_free() to deallocate the memory.
+ *
+ * \returns cat-value array with column values for each category
+ */
+static dbCatValArray *select_integers_from_database(dbDriver * driver,
+                                                    struct field_info *f_info,
+                                                    const char *column,
+                                                    const char *where)
+{
+    G_debug(1, "select_integers_from_database: column=%s", column);
+    dbCatValArray *column_values = G_malloc(sizeof(dbCatValArray));
+
+    /* check if column exists */
+    int ctype = db_column_Ctype(driver, f_info->table, column);
+
+    if (ctype == -1)
+        G_fatal_error(_("Column <%s> not found in table <%s>"),
+                      column, f_info->table);
+    if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
+        G_fatal_error(_("Only numeric column type is supported"));
+    if (ctype == DB_C_TYPE_DOUBLE)
+        G_warning(_("Double values will be converted to integers"));
+
+    db_CatValArray_init(column_values);
+    int nrec =
+        db_select_CatValArray(driver, f_info->table, f_info->key, column,
+                              where, column_values);
+
+    G_debug(2, "db_select_CatValArray() nrec = %d", nrec);
+    if (nrec < 0)
+        G_fatal_error(_("Unable to select data from table"));
+    return column_values;
+}
+
+/*! Get values in a column
+ *
+ * Checks the type of the column; fails with fatal for non-numeric columns
+ * and warns for floating point columns.
+ *
+ * \returns cat-value array with column values for each category
+ */
+static dbCatValArray *select_strings_from_database(dbDriver * driver,
+                                                   struct field_info *f_info,
+                                                   const char *column,
+                                                   const char *where)
+{
+    G_debug(1, "select_strings_from_database: column=%s", column);
+    dbCatValArray *column_values = G_malloc(sizeof(dbCatValArray));
+
+    /* check if column exists */
+    int ctype = db_column_Ctype(driver, f_info->table, column);
+
+    if (ctype == -1)
+        G_fatal_error(_("Column <%s> not found in table <%s>"),
+                      column, f_info->table);
+    if (ctype != DB_C_TYPE_STRING)
+        G_fatal_error(_("Only numeric column type is supported"));
+
+    db_CatValArray_init(column_values);
+    int nrec =
+        db_select_CatValArray(driver, f_info->table, f_info->key, column,
+                              where, column_values);
+
+    G_debug(2, "db_select_CatValArray() nrec = %d", nrec);
+    if (nrec < 0)
+        G_fatal_error(_("Unable to select data from table"));
+    return column_values;
+}
+
+/*! Get integer value in a column for a category
+ *
+ * Floating point numbers are casted to integers.
+ *
+ * \returns The value of the column as an integer
+ */
+static int get_integer_column_value(dbCatValArray * column_values, int cat)
+{
+    int val;
+    dbCatVal *catval;
+
+    if (db_CatValArray_get_value(column_values, cat, &catval) != DB_OK) {
+        G_fatal_error(_("No record for cat = %d"), cat);
+    }
+    if (catval->isNull) {
+        G_fatal_error(_("NULL value for cat = %d"), cat);
+    }
+    if (column_values->ctype == DB_C_TYPE_INT) {
+        val = catval->val.i;
+    }
+    else if (column_values->ctype == DB_C_TYPE_DOUBLE) {
+        val = catval->val.d;
+    }
+    /* else should be checked by caller */
+    return val;
+}
+
+/*! Get RGB in a column for a category as three integers
+ *
+ * Expects the column to be a string.
+ */
+static void get_color_column_value(dbCatValArray * cvarr, int cat,
+                                   int *red, int *green, int *blue)
+{
+    char colorstring[12];       /* RRR:GGG:BBB */
+    dbCatVal *value = NULL;
+
+    /* read RGB colors from db for current area # */
+    if (cvarr && db_CatValArray_get_value(cvarr, cat, &value) == DB_OK) {
+        sprintf(colorstring, "%s", db_get_string(value->val.s));
+        if (*colorstring != '\0') {
+            G_debug(5, "element: colorstring: %s", colorstring);
+            if (G_str_to_color(colorstring, red, green, blue) == 1) {
+                G_debug(5, "element: cat %d r:%d g:%d b:%d",
+                        cat, *red, *green, *blue);
+                /* TODO: handle return code 2 for none? */
+            }
+            else {
+                G_debug(5, "Invalid color definition '%s' ignored",
+                        colorstring);
+            }
+        }
+        else {
+            G_debug(5, "Invalid color definition '%s' ignored", colorstring);
+        }
+    }
+}
+
+static void load_columns(struct WriteContext *write_context,
+                         dbDriver * db_driver, struct field_info *f_info,
+                         struct LidarColumnNames *columns, const char *where)
+{
+    if (columns->return_n) {
+        write_context->return_column_values =
+            select_integers_from_database(db_driver, f_info,
+                                          columns->return_n, where);
+    }
+    if (columns->n_returns) {
+        write_context->n_returns_column_values =
+            select_integers_from_database(db_driver, f_info,
+                                          columns->n_returns, where);
+    }
+    if (columns->class_n) {
+        write_context->class_column_values =
+            select_integers_from_database(db_driver, f_info,
+                                          columns->class_n, where);
+    }
+    if (columns->grass_rgb) {
+        write_context->grass_rgb_column_values =
+            select_strings_from_database(db_driver, f_info,
+                                         columns->grass_rgb, where);
+    }
+    if (columns->red) {
+        write_context->red_column_values =
+            select_integers_from_database(db_driver, f_info,
+                                          columns->red, where);
+    }
+    if (columns->green) {
+        write_context->green_column_values =
+            select_integers_from_database(db_driver, f_info,
+                                          columns->green, where);
+    }
+    if (columns->blue) {
+        write_context->blue_column_values =
+            select_integers_from_database(db_driver, f_info,
+                                          columns->blue, where);
+    }
+}
+
+/*! Deallocate the memory for cat-value arrays */
+static void free_columns(struct WriteContext *write_context)
+{
+    if (write_context->return_column_values) {
+        db_CatValArray_free(write_context->return_column_values);
+        G_free(write_context->return_column_values);
+    }
+    if (write_context->n_returns_column_values) {
+        db_CatValArray_free(write_context->n_returns_column_values);
+        G_free(write_context->n_returns_column_values);
+    }
+    if (write_context->class_column_values) {
+        db_CatValArray_free(write_context->class_column_values);
+        G_free(write_context->class_column_values);
+    }
+    if (write_context->grass_rgb_column_values) {
+        db_CatValArray_free(write_context->grass_rgb_column_values);
+        G_free(write_context->grass_rgb_column_values);
+    }
+    if (write_context->red_column_values) {
+        db_CatValArray_free(write_context->red_column_values);
+        G_free(write_context->red_column_values);
+    }
+    if (write_context->green_column_values) {
+        db_CatValArray_free(write_context->green_column_values);
+        G_free(write_context->green_column_values);
+    }
+    if (write_context->blue_column_values) {
+        db_CatValArray_free(write_context->blue_column_values);
+        G_free(write_context->blue_column_values);
+    }
+}
+
+/*! Set point attributes from the attribute table
+ *
+ * All tables are taken from the context structure. The point and color
+ * are also taken from there.
+ */
+static void set_point_attributes_from_table(struct WriteContext *context,
+                                            int cat)
+{
+    LASPointH las_point = context->las_point;
+
+    if (context->return_column_values) {
+        int return_n =
+            get_integer_column_value(context->return_column_values, cat);
+        LASPoint_SetReturnNumber(las_point, return_n);
+    }
+    if (context->n_returns_column_values) {
+        int val =
+            get_integer_column_value(context->n_returns_column_values, cat);
+        LASPoint_SetNumberOfReturns(las_point, val);
+    }
+    if (context->class_column_values) {
+        int val = get_integer_column_value(context->class_column_values, cat);
+
+        LASPoint_SetClassification(las_point, val);
+    }
+    if (context->grass_rgb_column_values || context->red_column_values ||
+        context->green_column_values || context->blue_column_values) {
+        LASColorH las_color = context->las_color;
+
+        if (context->grass_rgb_column_values) {
+            int red, green, blue;
+
+            get_color_column_value(context->grass_rgb_column_values, cat,
+                                   &red, &green, &blue);
+            LASColor_SetRed(las_color, red);
+            LASColor_SetGreen(las_color, green);
+            LASColor_SetBlue(las_color, blue);
+        }
+        if (context->red_column_values) {
+            int val =
+                get_integer_column_value(context->red_column_values, cat);
+            LASColor_SetRed(las_color, val);
+        }
+        if (context->green_column_values) {
+            int val =
+                get_integer_column_value(context->green_column_values, cat);
+            LASColor_SetGreen(las_color, val);
+        }
+        if (context->blue_column_values) {
+            int val =
+                get_integer_column_value(context->blue_column_values, cat);
+            LASColor_SetBlue(las_color, val);
+        }
+        LASPoint_SetColor(las_point, las_color);
+    }
+}
+
+static void write_point(struct WriteContext *context, int cat, double x,
+                        double y, double z, struct line_cats *cats)
+{
+    LASPointH las_point = context->las_point;
+
+    LASPoint_SetX(las_point, x);
+    LASPoint_SetY(las_point, y);
+    LASPoint_SetZ(las_point, z);
+
+    /* only call when we actually using the attributes */
+    if (context->layer > 0)
+        set_point_attributes_from_table(context, cat);
+    /* after this point cat is used as a short term variable
+     * to store category to retrieve attributes */
+    
+    /* read color table */
+    if (context->color_table) {
+        int red, green, blue;
+        LASColorH las_color = context->las_color;
+        if (Rast_get_c_color(&cat, &red, &green, &blue, context->color_table) == 1) {
+            LASColor_SetRed(las_color, red);
+            LASColor_SetGreen(las_color, green);
+            LASColor_SetBlue(las_color, blue);
+            LASPoint_SetColor(las_point, las_color);
+        }
+        /* TODO: what else, fail, skip or put some defaults? */
+    }
+
+    if (context->return_layer) {
+        if (!Vect_cat_get(cats, context->return_layer, &cat))
+            return;             /* TODO: is this an error? */
+        LASPoint_SetReturnNumber(las_point, cat);
+    }
+    if (context->n_returns_layer) {
+        if (!Vect_cat_get(cats, context->n_returns_layer, &cat))
+            return;             /* TODO: is this an error? */
+        LASPoint_SetNumberOfReturns(las_point, cat);
+    }
+    if (context->class_layer) {
+        if (!Vect_cat_get(cats, context->class_layer, &cat))
+            return;             /* TODO: is this an error? */
+        LASPoint_SetClassification(las_point, cat);
+    }
+    if (context->rgb_layer || context->red_layer || context->green_layer ||
+        context->blue_layer) {
+        LASColorH las_color = context->las_color;
+
+        /* TODO: defaults for the color are what? */
+        /* TODO: check the range for RGB? */
+        if (context->rgb_layer) {
+            if (!Vect_cat_get(cats, context->rgb_layer, &cat))
+                return;         /* TODO: is this an error? */
+            int red = (cat >> 16) & 0xFF;
+            int green = (cat >> 8) & 0xFF;
+            int blue = cat & 0xFF;
+
+            LASColor_SetRed(las_color, red);
+            LASColor_SetGreen(las_color, green);
+            LASColor_SetBlue(las_color, blue);
+        }                       /* TODO: else all the others? */
+        if (context->red_layer) {
+            if (!Vect_cat_get(cats, context->red_layer, &cat))
+                return;         /* TODO: is this an error? */
+            LASColor_SetRed(las_color, cat);
+        }                       /* TODO: else set 0, or by default? */
+        if (context->green_layer) {
+            if (!Vect_cat_get(cats, context->green_layer, &cat))
+                return;         /* TODO: is this an error? */
+            LASColor_SetGreen(las_color, cat);
+        }
+        if (context->blue_layer) {
+            if (!Vect_cat_get(cats, context->blue_layer, &cat))
+                return;         /* TODO: is this an error? */
+            LASColor_SetBlue(las_color, cat);
+        }
+        LASPoint_SetColor(las_point, las_color);
+    }
+
+    LASError error = LASWriter_WritePoint(context->las_writer, las_point);
+
+    if (error)
+        G_fatal_error("Failure when writing a point");
+}
+
+
+/* TODO: these have overlap with vector lib, really needed? */
+static int point_in_region_2d(struct Cell_head *region, double x, double y)
+{
+    if (x > region->east || x < region->west || y < region->south ||
+        y > region->north)
+        return FALSE;
+    return TRUE;
+}
+
+
+int main(int argc, char **argv)
+{
+    struct GModule *module;
+    struct Option *map_opt, *foutput_opt;
+    struct Option *field_opt, *cats_opt;
+    struct Option *id_layer_opt, *class_layer_opt;
+    struct Option *return_layer_opt, *n_returns_layer_opt;
+    struct Option *red_layer_opt, *green_layer_opt, *blue_layer_opt;
+    struct Option *rgb_layer_opt;
+    struct Option *return_column_opt, *n_returns_column_opt;
+    struct Option *class_column_opt;
+    struct Option *grass_rgb_column_opt;
+    struct Option *red_column_opt, *green_column_opt, *blue_column_opt;
+    struct Option *where_opt;
+    struct Flag *region_flag, *no_color_table_flag;
+    struct Map_info vinput;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    G_add_keyword(_("vector"));
+    G_add_keyword(_("export"));
+    G_add_keyword(_("LIDAR"));
+    G_add_keyword(_("points"));
+    module->label = _("Exports vector points as LAS point cloud");
+    module->description = _("Converts LAS LiDAR point clouds to a GRASS"
+                            " vector map with libLAS");
+
+    map_opt = G_define_standard_option(G_OPT_V_INPUT);
+
+    field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
+    field_opt->required = NO;
+
+    foutput_opt = G_define_standard_option(G_OPT_F_OUTPUT);
+
+    cats_opt = G_define_standard_option(G_OPT_V_CATS);
+    cats_opt->guisection = _("Selection");
+
+    /* TODO: supported only when attributes are actually used */
+    where_opt = G_define_standard_option(G_OPT_DB_WHERE);
+    where_opt->guisection = _("Selection");
+
+    id_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    id_layer_opt->key = "id_layer";
+    id_layer_opt->label =
+        _("Layer number to store generated point ID as category");
+    id_layer_opt->answer = NULL;
+    id_layer_opt->guisection = _("Categories");
+
+    return_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    return_layer_opt->key = "return_layer";
+    return_layer_opt->label =
+        _("Layer number to store return number as category");
+    return_layer_opt->answer = NULL;
+    return_layer_opt->guisection = _("Categories");
+
+    n_returns_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    n_returns_layer_opt->key = "n_returns_layer";
+    n_returns_layer_opt->label =
+        _("Layer number to store return number as category");
+    n_returns_layer_opt->answer = NULL;
+    n_returns_layer_opt->guisection = _("Categories");
+
+    class_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    class_layer_opt->key = "class_layer";
+    class_layer_opt->label =
+        _("Layer number to store class number as category");
+    class_layer_opt->answer = NULL;
+    class_layer_opt->guisection = _("Categories");
+
+    rgb_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    rgb_layer_opt->key = "rgb_layer";
+    rgb_layer_opt->label =
+        _("Layer number where RGB color is stored as category");
+    rgb_layer_opt->answer = NULL;
+    rgb_layer_opt->guisection = _("Categories");
+
+    red_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    red_layer_opt->key = "red_layer";
+    red_layer_opt->label =
+        _("Layer number where red color is stored as category");
+    red_layer_opt->answer = NULL;
+    red_layer_opt->guisection = _("Categories");
+
+    green_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    green_layer_opt->key = "green_layer";
+    green_layer_opt->label =
+        _("Layer number where red color is stored as category");
+    green_layer_opt->answer = NULL;
+    green_layer_opt->guisection = _("Categories");
+
+    blue_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    blue_layer_opt->key = "blue_layer";
+    blue_layer_opt->label =
+        _("Layer number where blue color is stored as category");
+    blue_layer_opt->answer = NULL;
+    blue_layer_opt->guisection = _("Categories");
+
+    /* TODO: probably replace the option by standardized/expected column names */
+
+    return_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
+    return_column_opt->key = "return_column";
+    return_column_opt->label = _("Column with return number");
+    return_column_opt->required = NO;
+    return_column_opt->guisection = _("Columns");
+
+    n_returns_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
+    n_returns_column_opt->key = "n_returns_column";
+    n_returns_column_opt->label = _("Column with return number");
+    n_returns_column_opt->required = NO;
+    n_returns_column_opt->guisection = _("Columns");
+
+    class_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
+    class_column_opt->key = "class_column";
+    class_column_opt->label = _("Column with return number");
+    class_column_opt->required = NO;
+    class_column_opt->guisection = _("Columns");
+
+    grass_rgb_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
+    grass_rgb_column_opt->key = "rgb_column";
+    grass_rgb_column_opt->label = _("RGB color definition column");
+    grass_rgb_column_opt->description = _("Color definition in R:G:B form");
+    grass_rgb_column_opt->required = NO;
+    grass_rgb_column_opt->guisection = _("Columns");
+
+    red_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
+    red_column_opt->key = "red_column";
+    red_column_opt->label = _("Column with red color");
+    red_column_opt->required = NO;
+    red_column_opt->guisection = _("Columns");
+
+    green_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
+    green_column_opt->key = "green_column";
+    green_column_opt->label = _("Column with green color");
+    green_column_opt->required = NO;
+    green_column_opt->guisection = _("Columns");
+
+    blue_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
+    blue_column_opt->key = "blue_column";
+    blue_column_opt->label = _("Column with blue color");
+    blue_column_opt->required = NO;
+    blue_column_opt->guisection = _("Columns");
+
+    region_flag = G_define_flag();
+    region_flag->key = 'r';
+    region_flag->guisection = _("Selection");
+    region_flag->description = _("Limit export to the current region");
+
+    no_color_table_flag = G_define_flag();
+    no_color_table_flag->key = 'w';
+    no_color_table_flag->label = _("Ignore color table");
+    no_color_table_flag->description =
+        _("Ignore color table even when set and not other options are present");
+
+
+    if (G_parser(argc, argv))
+        exit(EXIT_FAILURE);
+
+    /* TODO: layer required > 0 with columns */
+
+    /* TODO: do some check */
+    /*Vect_check_input_output_name(map_opt->answer, voutput_opt->answer,
+       G_FATAL_EXIT);
+     */
+
+    if (Vect_open_old2(&vinput, map_opt->answer, "", field_opt->answer) < 0)
+        G_fatal_error(_("Unable to open vector map <%s>"), map_opt->answer);
+    int layer = Vect_get_field_number(&vinput, field_opt->answer);
+
+    struct cat_list *allowed_cats = NULL;
+
+    if (layer > 0)
+        allowed_cats = Vect_cats_set_constraint(&vinput, layer, NULL,
+                                                cats_opt->answer);
+
+    struct line_pnts *line = Vect_new_line_struct();
+    struct line_cats *cats = Vect_new_cats_struct();
+
+    struct Cell_head comp_region;
+
+    G_get_window(&comp_region);
+
+    struct WriteContext write_context;
+
+    write_context.return_layer = 0;
+    write_context.n_returns_layer = 0;
+    write_context.class_layer = 0;
+    write_context.rgb_layer = 0;
+    write_context.red_layer = 0;
+    write_context.green_layer = 0;
+    write_context.blue_layer = 0;
+    if (return_layer_opt->answer)
+        write_context.return_layer = atoi(return_layer_opt->answer);
+    if (n_returns_layer_opt->answer)
+        write_context.n_returns_layer = atoi(n_returns_layer_opt->answer);
+    if (class_layer_opt->answer)
+        write_context.class_layer = atoi(class_layer_opt->answer);
+    if (rgb_layer_opt->answer)
+        write_context.rgb_layer = atoi(rgb_layer_opt->answer);
+    if (red_layer_opt->answer)
+        write_context.red_layer = atoi(red_layer_opt->answer);
+    if (green_layer_opt->answer)
+        write_context.green_layer = atoi(green_layer_opt->answer);
+    if (blue_layer_opt->answer)
+        write_context.blue_layer = atoi(blue_layer_opt->answer);
+
+    /* get GRASS loc proj info */
+    struct Key_Value *proj_info;
+    struct Key_Value *proj_units;
+
+    /* TODO: should we test for PROJECTION_XY? */
+    proj_info = G_get_projinfo();
+    proj_units = G_get_projunits();
+    char *current_wkt = GPJ_grass_to_wkt(proj_info, proj_units, FALSE, FALSE);
+
+    G_free_key_value(proj_info);
+    G_free_key_value(proj_units);
+
+    /* TODO: ignoring errors */
+    LASWriterH las_writer;
+    LASHeaderH las_header = LASHeader_Create();
+    LASSRSH las_srs = LASSRS_Create();
+
+    LASSRS_SetWKT(las_srs, current_wkt);
+    LASHeader_SetSRS(las_header, las_srs);
+    /* TODO: support append mode */
+    int write_mode = 1;
+
+    las_writer = LASWriter_Create(foutput_opt->answer,
+                                  las_header, write_mode);
+    write_context.las_writer = las_writer;
+
+    /* to avoid allocation for each point we are writing */
+    write_context.las_point = LASPoint_Create();
+    LASPoint_SetHeader(write_context.las_point, las_header);
+    write_context.las_color = LASColor_Create();
+
+    write_context.layer = layer;
+    write_context.return_column_values = 0;
+    write_context.n_returns_column_values = 0;
+    write_context.class_column_values = 0;
+    write_context.grass_rgb_column_values = 0;
+    write_context.red_column_values = 0;
+    write_context.green_column_values = 0;
+    write_context.blue_column_values = 0;
+    /* TODO: limit select by the cat values */
+    /* TODO: limit select by 2D/3D region and zrange, possible? */
+
+    int use_color_attributes = FALSE;
+
+    if (return_column_opt->answer || n_returns_column_opt->answer
+        || class_column_opt->answer || grass_rgb_column_opt->answer
+        || red_column_opt->answer || green_column_opt->answer
+        || blue_column_opt->answer) {
+        dbDriver *db_driver;
+        struct field_info *f_info;
+
+        struct LidarColumnNames column_names;
+
+        column_names.return_n = return_column_opt->answer;
+        column_names.n_returns = n_returns_column_opt->answer;
+        column_names.class_n = class_column_opt->answer;
+        column_names.grass_rgb = grass_rgb_column_opt->answer;
+        column_names.red = red_column_opt->answer;
+        column_names.green = green_column_opt->answer;
+        column_names.blue = blue_column_opt->answer;
+
+        open_database(&vinput, layer, &db_driver, &f_info);
+        load_columns(&write_context, db_driver, f_info, &column_names,
+                     where_opt->answer);
+        close_database(db_driver);
+        
+        if ( grass_rgb_column_opt->answer || red_column_opt->answer || green_column_opt->answer || blue_column_opt->answer)
+            use_color_attributes = TRUE;
+    }
+
+    struct Colors color_table;
+    write_context.color_table = 0;
+    if (!use_color_attributes && !no_color_table_flag->answer && !(write_context.rgb_layer || write_context.red_layer || write_context.green_layer || write_context.blue_layer)) {
+        int has_colors = Vect_read_colors(Vect_get_name(&vinput), Vect_get_mapset(&vinput), &color_table);
+        if (has_colors)
+            write_context.color_table = &color_table;
+    }
+
+    /* some constraints can be set on the map */
+    Vect_set_constraint_type(&vinput, GV_POINT);
+    /* noop for layer=-1 and non-native format, skips lines without cat */
+    Vect_set_constraint_field(&vinput, layer);
+    /* TODO: replace region checks by Vect_set_constraint_region? */
+
+    int ltype;
+    int cat;
+
+    while (TRUE) {
+        ltype = Vect_read_next_line(&vinput, line, cats);
+        if (ltype == -1)
+            G_fatal_error(_("Unable to read vector map"));
+        if (ltype == -2)
+            break;              /* end of the map */
+
+        double x, y, z;
+
+        Vect_line_get_point(line, 0, &x, &y, &z);
+
+        /* selections/filters */
+        /* TODO: use region only when actually needed */
+        if (region_flag->answer && !point_in_region_2d(&comp_region, x, y))
+            continue;
+        if (allowed_cats &&
+            !Vect_cats_in_constraint(cats, layer, allowed_cats))
+            continue;
+
+        /* TODO: test: skip points without category, unless layer=-1 */
+        /* Use cases:
+         * - all points have category (correct)
+         * - no categories for any point (correct, layer=-1 required)
+         * - some points miss category (not handled)
+         * Here we assume that there is only one set of attributes for one point.
+         * If no layer available, cat contains junk and shouldn't be used.
+         */
+        if (layer > 0)
+            Vect_cat_get(cats, layer, &cat);
+
+        write_point(&write_context, cat, x, y, z, cats);
+    }
+
+    /* partially unnecessary as deallocated by the system */
+    Vect_destroy_line_struct(line);
+    Vect_destroy_cats_struct(cats);
+    Vect_close(&vinput);
+
+    free_columns(&write_context);
+
+    LASPoint_Destroy(write_context.las_point);
+    LASColor_Destroy(write_context.las_color);
+    LASWriter_Destroy(write_context.las_writer);
+    LASSRS_Destroy(las_srs);
+
+    return EXIT_SUCCESS;
+}


Property changes on: grass/trunk/vector/v.out.lidar/main.c
___________________________________________________________________
Added: svn:mime-type
   + text/x-csrc
Added: svn:eol-style
   + native

Added: grass/trunk/vector/v.out.lidar/v.out.lidar.html
===================================================================
--- grass/trunk/vector/v.out.lidar/v.out.lidar.html	                        (rev 0)
+++ grass/trunk/vector/v.out.lidar/v.out.lidar.html	2015-11-17 02:34:01 UTC (rev 66855)
@@ -0,0 +1,45 @@
+<h2>DESCRIPTION</h2>
+
+<em>v.out.lidar</em> converts GRASS vector map to a LiDAR point clouds
+in LAS format using the <a href="http://www.liblas.org">libLAS</a> library.
+
+<p>
+The <b>-r</b> flag limits the export to the current computational region
+extent (see <em><a href="g.region.html">g.region</a></em>).
+The <b>where</b> option limits the export by attributes (applied only
+when the columns are used for export).
+
+
+<h2>NOTES</h2>
+
+The typical file extensions for the LAS format are .las and .laz (compressed).
+The compressed LAS (.laz) format can be exported only if libLAS has been
+compiled with <a href="http://www.laszip.org/">LASzip</a> support.
+It is also good when libLAS was compiled with GDAL. This is needed when
+working with projections.
+
+
+<h2>EXAMPLE</h2>
+
+Generate fractal surface and export is as point in LAS format:
+
+<div class="code"><pre>
+g.region raster=elevation res=100
+r.surf.fractal output=fractals
+r.to.vect input=fractals output=fractals type=point -z
+v.out.lidar input=fractals output=fractals.las
+</pre></div>
+
+
+<h2>REFERENCES</h2>
+
+<a href="http://www.asprs.org/Committee-General/LASer-LAS-File-Format-Exchange-Activities.html">
+ASPRS LAS format</a><br>
+<a href="http://www.liblas.org/">LAS library</a> <br>
+
+
+<h2>AUTHOR</h2>
+
+Vaclav Petras
+
+<p><i>Last changed: $Date$</i>


Property changes on: grass/trunk/vector/v.out.lidar/v.out.lidar.html
___________________________________________________________________
Added: svn:mime-type
   + text/html
Added: svn:keywords
   + Author Date Id
Added: svn:eol-style
   + native



More information about the grass-commit mailing list