Sfoglia il codice sorgente

v.in.lidar, v.out.lidar, v.in.pdal: unify layer and category handling

User has now option to store generated ID, first/mid/last
return info, class and RGB (as on number) as category 
in custom layers. Autogenerated ID/cat is stored by default
and can be disabled by setting option to empty string
(and unofficially also to 0).

This removes extra layers like red or return number
and also flags related to storing category.

User has now full control over creating layers
but the number of layers and options is minimal.

For v.out.lidar the created LAS is limited but
full options (e.g. arbitrary numbers for returns)
are possible using attribute table.

This simplifies https://trac.osgeo.org/grass/changeset/66343, https://trac.osgeo.org/grass/changeset/67159 in v.in.lidar.

v.in.pdal now stores ID/cat by default
to be consistent with v.in.lidar.


git-svn-id: https://svn.osgeo.org/grass/grass/trunk@68469 15284696-431f-4ddb-bdfa-cd5b030d7da7
Vaclav Petras 9 anni fa
parent
commit
16cc578e70

+ 10 - 0
vector/v.in.lidar/lidar.c

@@ -39,3 +39,13 @@ struct class_table class_type[] = {
     {7, "Withheld"},
     {0, 0}
 };
+
+int return_to_cat(int return_n, int n_returns)
+{
+    if (return_n == 1)
+        return LAS_FIRST;
+    else if (n_returns > 1 && return_n == n_returns)
+            return LAS_LAST;
+    else
+        return LAS_MID;
+}

+ 2 - 0
vector/v.in.lidar/lidar.h

@@ -66,4 +66,6 @@ struct class_table
 extern struct class_table class_val[];
 extern struct class_table class_type[];
 
+int return_to_cat(int return_n, int n_returns);
+
 #endif /* GRASS_LIDAR_H */

+ 18 - 106
vector/v.in.lidar/main.c

@@ -47,15 +47,14 @@ int main(int argc, char *argv[])
     float xmin = 0., ymin = 0., xmax = 0., ymax = 0.;
     struct GModule *module;
     struct Option *in_opt, *out_opt, *spat_opt, *filter_opt, *class_opt;
-    struct Option *id_layer_opt, *return_layer_opt, *n_returns_layer_opt;
+    struct Option *id_layer_opt;
+    struct Option *return_layer_opt;
     struct Option *class_layer_opt;
-    struct Option *red_layer_opt, *green_layer_opt, *blue_layer_opt;
     struct Option *rgb_layer_opt;
     struct Option *vector_mask_opt, *vector_mask_field_opt;
     struct Option *skip_opt, *preserve_opt, *offset_opt, *limit_opt;
     struct Option *outloc_opt, *zrange_opt;
     struct Flag *print_flag, *notab_flag, *region_flag, *notopo_flag;
-    struct Flag *nocats_flag;
     struct Flag *over_flag, *extend_flag, *no_import_flag;
     struct Flag *invert_mask_flag;
     char buf[2000];
@@ -119,58 +118,35 @@ int main(int argc, char *argv[])
     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->description =
+        _("Set empty to not store it. Required for attribute table.");
+    id_layer_opt->answer = "1";
     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");
+        _("Layer number to store return information as category");
+    return_layer_opt->description = _("Leave empty to not store it");
     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 number of returns 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->description = _("Leave empty to not store it");
     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 RBG colors is stored as category");
+        _("Layer number where RBG colors are stored as category");
+    rgb_layer_opt->description = _("Leave empty to not store it");
     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");
-
     spat_opt = G_define_option();
     spat_opt->key = "spatial";
     spat_opt->type = TYPE_DOUBLE;
@@ -290,14 +266,6 @@ int main(int argc, char *argv[])
     notab_flag = G_define_standard_flag(G_FLG_V_TABLE);
     notab_flag->guisection = _("Speed");
 
-    nocats_flag = G_define_flag();
-    nocats_flag->key = 'c';
-    nocats_flag->label =
-        _("Store only the coordinates");
-    nocats_flag->description =
-        _("Do not add categories to points and do not create attribute table");
-    nocats_flag->guisection = _("Speed");
-
     notopo_flag = G_define_standard_flag(G_FLG_V_TOPO);
     notopo_flag->guisection = _("Speed");
 
@@ -316,9 +284,6 @@ int main(int argc, char *argv[])
     no_import_flag->suppress_required = YES;
 
     G_option_exclusive(skip_opt, preserve_opt, NULL);
-    G_option_excludes(nocats_flag, id_layer_opt, return_layer_opt,
-        n_returns_layer_opt, class_layer_opt, rgb_layer_opt,
-        red_layer_opt, green_layer_opt, blue_layer_opt, NULL);
 
     /* The parser checks if the map already exists in current mapset, this is
      * wrong if location options is used, so we switch out the check and do it
@@ -328,10 +293,6 @@ int main(int argc, char *argv[])
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
 
-    /* no cats implies no table */
-    if (nocats_flag->answer)
-        notab_flag->answer = 1;
-
     /* Don't crash on cmd line if file not found */
     if (access(in_opt->answer, F_OK) != 0) {
 	G_fatal_error(_("Input file <%s> does not exist"), in_opt->answer);
@@ -379,62 +340,20 @@ int main(int argc, char *argv[])
 
     int id_layer = 0;
     int return_layer = 0;
-    int n_returns_layer = 0;
     int class_layer = 0;
     int rgb_layer = 0;
-    int red_layer = 0;
-    int green_layer = 0;
-    int blue_layer = 0;
     if (id_layer_opt->answer)
         id_layer = atoi(id_layer_opt->answer);
     if (return_layer_opt->answer)
         return_layer = atoi(return_layer_opt->answer);
-    if (n_returns_layer_opt->answer)
-        n_returns_layer = atoi(n_returns_layer_opt->answer);
     if (class_layer_opt->answer)
         class_layer = atoi(class_layer_opt->answer);
     if (rgb_layer_opt->answer)
         rgb_layer = atoi(rgb_layer_opt->answer);
-    if (red_layer_opt->answer)
-        red_layer = atoi(red_layer_opt->answer);
-    if (green_layer_opt->answer)
-        green_layer = atoi(green_layer_opt->answer);
-    if (blue_layer_opt->answer)
-        blue_layer = atoi(blue_layer_opt->answer);
-    /* If no layer specified by user, force 1 to be used for ids.
-     * If id_layer not specified by the attributes table was, find a layer.
-     * nocats implies notab and we don't add any layers.
-     * Also when layers are set to zero by user, we consider it as if
-     * the nocats flag would be specified. We use !id_layer_opt->answer
-     * to see that user was the one not setting the id_layer which are
-     * are about to turn on.
-     * Later on, layer set to 0 is considered as no layer set.
-     */
-    if (!nocats_flag->answer && !id_layer_opt->answer && !return_layer
-        && !n_returns_layer && !class_layer && !rgb_layer && !red_layer
-        && !green_layer && !blue_layer) {
-        id_layer = 1;
-        G_message(_("Storing generated point IDs as categories in the layer %d"), id_layer);
-    }
     /* no cats forces no table earlier */
     if (!notab_flag->answer && !id_layer) {
-        /* get the maximum layer number used */
-        int max_used_layer;
-        max_used_layer = MAX(return_layer, n_returns_layer);
-        max_used_layer = MAX(max_used_layer, class_layer);
-        max_used_layer = MAX(max_used_layer, rgb_layer);
-        max_used_layer = MAX(max_used_layer, red_layer);
-        max_used_layer = MAX(max_used_layer, green_layer);
-        max_used_layer = MAX(max_used_layer, blue_layer);
-        /* get the first free layer number */
-        for (i = 1; i <= max_used_layer + 1; i++) {
-            if (i != return_layer && i != n_returns_layer
-                && i != class_layer && i != rgb_layer
-                && i != red_layer && i != green_layer && i != blue_layer)
-                break;
-        }
-        id_layer = i;
-        G_message(_("Storing generated point IDs as categories in the layer %d"), id_layer);
+        G_message(_("-%c flag is not set but ID layer is not specified"), notab_flag->key);
+        G_fatal_error(_("ID layer is required to store attribute table"));
     }
 
     double zrange_min, zrange_max;
@@ -672,15 +591,14 @@ int main(int argc, char *argv[])
 	Vect_append_point(Points, x, y, z);
         if (id_layer)
             Vect_cat_set(Cats, id_layer, cat);
-        if (return_layer)
-            Vect_cat_set(Cats, return_layer, LASPoint_GetReturnNumber(LAS_point));
-        if (n_returns_layer)
-            Vect_cat_set(Cats, n_returns_layer, LASPoint_GetNumberOfReturns(LAS_point));
+        if (return_layer) {
+            int return_c = return_to_cat(return_n, n_returns);
+            Vect_cat_set(Cats, return_layer, return_c);
+        }
         if (class_layer)
-            Vect_cat_set(Cats, class_layer, LASPoint_GetClassification(LAS_point));
-        if (have_color && (rgb_layer || red_layer || green_layer || blue_layer)) {
+            Vect_cat_set(Cats, class_layer, point_class);
+        if (have_color && rgb_layer) {
             /* TODO: if attr table, acquired again, performance difference? */
-            /* TODO: the getters are called too when separate layers are used */
             LASColorH LAS_color = LASPoint_GetColor(LAS_point);
             if (rgb_layer) {
                 int red = LASColor_GetRed(LAS_color);
@@ -691,12 +609,6 @@ int main(int argc, char *argv[])
                 rgb = (rgb << 8) + blue;
                 Vect_cat_set(Cats, rgb_layer, rgb);
             }
-            if (red_layer)
-                Vect_cat_set(Cats, red_layer, LASColor_GetRed(LAS_color));
-            if (green_layer)
-                Vect_cat_set(Cats, green_layer, LASColor_GetGreen(LAS_color));
-            if (blue_layer)
-                Vect_cat_set(Cats, blue_layer, LASColor_GetBlue(LAS_color));
         }
 	Vect_write_line(&Map, GV_POINT, Points, Cats);
 

+ 10 - 28
vector/v.in.pdal/lidar.c

@@ -15,40 +15,12 @@
 
 #include "lidar.h"
 
-void GLidarLayers_set_default_layers(struct GLidarLayers *layers)
-{
-    layers->id_layer = 0;
-    layers->return_layer = G_RETURN_LAYER;
-    layers->n_returns_layer = G_NUM_RETURNS_LAYER;
-    layers->class_layer = G_CLASS_LAYER;
-    layers->rgb_layer = G_RGB_LAYER;
-    layers->red_layer = 0;
-    layers->green_layer = 0;
-    layers->blue_layer = 0;
-}
-
-void GLidarLayers_set_all_layers(struct GLidarLayers *layers)
-{
-    layers->id_layer = G_ID_LAYER;
-    layers->return_layer = G_RETURN_LAYER;
-    layers->n_returns_layer = G_NUM_RETURNS_LAYER;
-    layers->class_layer = G_CLASS_LAYER;
-    layers->rgb_layer = G_RGB_LAYER;
-    layers->red_layer = G_RED_LAYER;
-    layers->green_layer = G_GREEN_LAYER;
-    layers->blue_layer = G_BLUE_LAYER;
-}
-
 void GLidarLayers_set_no_layers(struct GLidarLayers *layers)
 {
     layers->id_layer = 0;
     layers->return_layer = 0;
-    layers->n_returns_layer = 0;
     layers->class_layer = 0;
     layers->rgb_layer = 0;
-    layers->red_layer = 0;
-    layers->green_layer = 0;
-    layers->blue_layer = 0;
 }
 
 struct class_table class_val[] = {
@@ -75,3 +47,13 @@ struct class_table class_type[] = {
     {7, "Withheld"},
     {0, 0}
 };
+
+int return_to_cat(int return_n, int n_returns)
+{
+    if (return_n == 1)
+        return LAS_FIRST;
+    else if (n_returns > 1 && return_n == n_returns)
+            return LAS_LAST;
+    else
+        return LAS_MID;
+}

+ 2 - 15
vector/v.in.pdal/lidar.h

@@ -21,29 +21,14 @@
 #define LAS_LAST 2
 #define LAS_MID 3
 
-#define G_ID_LAYER 1
-#define G_RETURN_LAYER 2
-#define G_NUM_RETURNS_LAYER 3
-#define G_CLASS_LAYER 4
-#define G_RGB_LAYER 5
-#define G_RED_LAYER 6
-#define G_GREEN_LAYER 7
-#define G_BLUE_LAYER 8
-
 struct GLidarLayers
 {
     int id_layer;
     int return_layer;
-    int n_returns_layer;
     int class_layer;
     int rgb_layer;
-    int red_layer;
-    int green_layer;
-    int blue_layer;
 };
 
-void GLidarLayers_set_default_layers(struct GLidarLayers *layers);
-void GLidarLayers_set_all_layers(struct GLidarLayers *layers);
 void GLidarLayers_set_no_layers(struct GLidarLayers *layers);
 
 /*
@@ -91,4 +76,6 @@ struct class_table
 extern struct class_table class_val[];
 extern struct class_table class_type[];
 
+int return_to_cat(int return_n, int n_returns);
+
 #endif /* GRASS_LIDAR_H */

+ 67 - 55
vector/v.in.pdal/main.cpp

@@ -42,16 +42,16 @@ void pdal_point_to_grass(struct Map_info *output_vector,
     double y = point_view->getFieldAs<double>(Y, idx);
     double z = point_view->getFieldAs<double>(dim_to_use_as_z, idx);
 
+    /* TODO: optimize for case with no layers, by adding
+     * and if to skip all the other ifs */
     if (layers->id_layer) {
         Vect_cat_set(cats, layers->id_layer, cat);
     }
     if (layers->return_layer) {
-        Vect_cat_set(cats, layers->return_layer,
-                     point_view->getFieldAs<int>(ReturnNumber, idx));
-    }
-    if (layers->n_returns_layer) {
-        Vect_cat_set(cats, layers->n_returns_layer,
-                     point_view->getFieldAs<int>(NumberOfReturns, idx));
+        int return_n = point_view->getFieldAs<int>(ReturnNumber, idx);
+        int n_returns = point_view->getFieldAs<int>(NumberOfReturns, idx);
+        int return_c = return_to_cat(return_n, n_returns);
+        Vect_cat_set(cats, layers->return_layer, return_c);
     }
     if (layers->class_layer) {
         Vect_cat_set(cats, layers->class_layer,
@@ -66,18 +66,6 @@ void pdal_point_to_grass(struct Map_info *output_vector,
         rgb = (rgb << 8) + blue;
         Vect_cat_set(cats, layers->rgb_layer, rgb);
     }
-    if (layers->red_layer) {
-        Vect_cat_set(cats, layers->red_layer,
-                     point_view->getFieldAs<int>(Red, idx));
-    }
-    if (layers->green_layer) {
-        Vect_cat_set(cats, layers->green_layer,
-                     point_view->getFieldAs<int>(Green, idx));
-    }
-    if (layers->blue_layer) {
-        Vect_cat_set(cats, layers->blue_layer,
-                     point_view->getFieldAs<int>(Blue, idx));
-    }
 
     Vect_append_point(points, x, y, z);
     Vect_write_line(output_vector, GV_POINT, points, cats);
@@ -102,6 +90,38 @@ int main(int argc, char *argv[])
 
     Option *out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
 
+    Option *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->description =
+        _("Set empty to not store it. Required for attribute table.");
+    id_layer_opt->answer = "1";
+    id_layer_opt->guisection = _("Categories");
+
+    Option *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 information as category");
+    return_layer_opt->description = _("Leave empty to not store it");
+    return_layer_opt->answer = NULL;
+    return_layer_opt->guisection = _("Categories");
+
+    Option *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->description = _("Leave empty to not store it");
+    class_layer_opt->answer = NULL;
+    class_layer_opt->guisection = _("Categories");
+
+    Option *rgb_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
+    rgb_layer_opt->key = "rgb_layer";
+    rgb_layer_opt->label =
+        _("Layer number where RBG colors are stored as category");
+    rgb_layer_opt->description = _("Leave empty to not store it");
+    rgb_layer_opt->answer = NULL;
+    rgb_layer_opt->guisection = _("Categories");
+
     Option *spatial_opt = G_define_option();
     spatial_opt->key = "spatial";
     spatial_opt->type = TYPE_DOUBLE;
@@ -220,20 +240,6 @@ int main(int argc, char *argv[])
     region_flag->guisection = _("Selection");
     region_flag->description = _("Limit import to the current region");
 
-    Flag *nocats_flag = G_define_flag();
-    nocats_flag->key = 'c';
-    nocats_flag->label =
-        _("Store only the coordinates");
-    nocats_flag->description =
-        _("Do not add any categories to points");
-    nocats_flag->guisection = _("Categories");
-
-    Flag *idcat_flag = G_define_flag();
-    idcat_flag->key = 'd';
-    idcat_flag->label =
-        _("Store generated unique ID for each point");
-    idcat_flag->guisection = _("Categories");
-
     Flag *extract_ground_flag = G_define_flag();
     extract_ground_flag->key = 'j';
     extract_ground_flag->label =
@@ -268,7 +274,6 @@ int main(int argc, char *argv[])
 
     G_option_exclusive(spatial_opt, region_flag, NULL);
     G_option_exclusive(reproject_flag, over_flag, NULL);
-    G_option_exclusive(nocats_flag, idcat_flag, NULL);
     G_option_exclusive(extract_ground_flag, classify_ground_flag, NULL);
 
     if (G_parser(argc, argv))
@@ -281,6 +286,17 @@ int main(int argc, char *argv[])
     // we use full qualification because the dim ns conatins too general names
     pdal::Dimension::Id::Enum dim_to_use_as_z = pdal::Dimension::Id::Z;
 
+    struct GLidarLayers layers;
+    GLidarLayers_set_no_layers(&layers);
+    if (id_layer_opt->answer && id_layer_opt->answer[0] != '\0')
+        layers.id_layer = std::stoi(id_layer_opt->answer);
+    if (return_layer_opt->answer && return_layer_opt->answer[0] != '\0')
+        layers.return_layer = std::stoi(return_layer_opt->answer);
+    if (class_layer_opt->answer && class_layer_opt->answer[0] != '\0')
+        layers.class_layer = std::stoi(class_layer_opt->answer);
+    if (rgb_layer_opt->answer && rgb_layer_opt->answer[0] != '\0')
+        layers.rgb_layer = std::stoi(rgb_layer_opt->answer);
+
     double xmin = 0;
     double ymin = 0;
     double xmax = 0;
@@ -417,9 +433,6 @@ int main(int argc, char *argv[])
     // TODO: the falses for filters should be perhaps fatal error
     // (bad input) or warning if filter was requested by the user
 
-    struct GLidarLayers layers;
-    GLidarLayers_set_default_layers(&layers);
-
     // update layers we are writting based on what is in the data
     // update usage of our filters as well
     if (point_view->hasDim(pdal::Dimension::Id::ReturnNumber) &&
@@ -427,8 +440,11 @@ int main(int argc, char *argv[])
         use_return_filter = true;
     }
     else {
-        layers.return_layer = 0;
-        layers.n_returns_layer = 0;
+        if (layers.return_layer) {
+            layers.return_layer = 0;
+            G_warning(_("Cannot store return information because the"
+                        " input does not have a return dimensions"));
+        }
         use_return_filter = false;
     }
 
@@ -436,26 +452,22 @@ int main(int argc, char *argv[])
         use_class_filter = true;
     }
     else {
-        layers.class_layer = 0;
+        if (layers.class_layer) {
+            layers.class_layer = 0;
+            G_warning(_("Cannot store class because the input"
+                        " does not have a classification dimension"));
+        }
         use_class_filter = false;
     }
 
     if (!(point_view->hasDim(pdal::Dimension::Id::Red) &&
-            point_view->hasDim(pdal::Dimension::Id::Green) &&
-            point_view->hasDim(pdal::Dimension::Id::Blue) &&
-            (layers.rgb_layer || layers.red_layer
-             || layers.green_layer || layers.blue_layer))) {
-        layers.rgb_layer = 0;
-        layers.red_layer = 0;
-        layers.green_layer = 0;
-        layers.blue_layer = 0;
-    }
-    if (idcat_flag->answer)
-        layers.id_layer = G_ID_LAYER;
-
-    // we just force it without any checking (we rely on the options)
-    if (nocats_flag->answer) {
-        GLidarLayers_set_no_layers(&layers);
+          point_view->hasDim(pdal::Dimension::Id::Green) &&
+          point_view->hasDim(pdal::Dimension::Id::Blue))) {
+        if (layers.rgb_layer) {
+            layers.rgb_layer = 0;
+            G_warning(_("Cannot store RGB colors because the input"
+                        " does not have a RGB dimensions"));
+        }
     }
 
     G_important_message(_("Scanning points..."));
@@ -534,7 +546,7 @@ int main(int argc, char *argv[])
         pdal_point_to_grass(&output_vector, points, cats, point_view,
                             idx, &layers, cat, dim_to_use_as_z);
         if (layers.id_layer) {
-            // TODO: perhaps it would be better to use the max cat afterwords
+            // TODO: perhaps it would be better to use the max cat afterwards
             if (cat == GV_CAT_MAX) {
                 cat_max_reached = true;
                 break;

+ 23 - 72
vector/v.out.lidar/main.c

@@ -27,6 +27,9 @@
 
 #include <liblas/capi/liblas.h>
 
+#define LAS_FIRST 1
+#define LAS_LAST 2
+#define LAS_MID 3
 
 struct WriteContext
 {
@@ -36,12 +39,8 @@ struct WriteContext
     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;
@@ -393,20 +392,24 @@ static void write_point(struct WriteContext *context, int cat, double x,
     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);
+        /* TODO: use LAS... as constants for numbers */
+        if (cat == LAS_FIRST) {
+            LASPoint_SetReturnNumber(las_point, 1);
+            LASPoint_SetNumberOfReturns(las_point, 3);
+        } else if (cat == LAS_LAST) {
+            LASPoint_SetReturnNumber(las_point, 3);
+            LASPoint_SetNumberOfReturns(las_point, 3);
+        } else {
+            LASPoint_SetReturnNumber(las_point, 2);
+            LASPoint_SetNumberOfReturns(las_point, 3);
+        }
     }
     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) {
+    if (context->rgb_layer) {
         LASColorH las_color = context->las_color;
 
         /* TODO: defaults for the color are what? */
@@ -422,21 +425,6 @@ static void write_point(struct WriteContext *context, int cat, double x,
             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);
     }
 
@@ -462,9 +450,9 @@ 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 *id_layer_opt;
+    struct Option *return_layer_opt;
+    struct Option *class_layer_opt;
     struct Option *rgb_layer_opt;
     struct Option *return_column_opt, *n_returns_column_opt;
     struct Option *class_column_opt;
@@ -514,13 +502,6 @@ int main(int argc, char **argv)
     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 =
@@ -535,27 +516,6 @@ int main(int argc, char **argv)
     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);
@@ -663,26 +623,14 @@ int main(int argc, char **argv)
     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;
@@ -758,8 +706,11 @@ int main(int argc, char **argv)
 
     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 (!use_color_attributes && !no_color_table_flag->answer
+        && !(write_context.rgb_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;
     }