Advertisement
jiapei100

grass/vector/v.in.pdal/main.cpp

Feb 22nd, 2018
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 26.13 KB | None | 0 0
  1. #include <pdal/Dimension.hpp>
  2. #include <pdal/PointTable.hpp>
  3. #include <pdal/PointView.hpp>
  4. #include <pdal/StageFactory.hpp>
  5. #include <pdal/io/LasReader.hpp>
  6. #include <pdal/io/LasHeader.hpp>
  7. #include <pdal/Options.hpp>
  8. #include <pdal/filters/ReprojectionFilter.hpp>
  9.  
  10. extern "C"
  11. {
  12. #include <grass/gis.h>
  13. #include <grass/vector.h>
  14. #include <grass/gprojects.h>
  15. #include <grass/glocale.h>
  16. }
  17.  
  18. extern "C"
  19. {
  20. #include "lidar.h"
  21. #include "projection.h"
  22. #include "filters.h"
  23. }
  24.  
  25. #ifdef HAVE_LONG_LONG_INT
  26. typedef unsigned long long gpoint_count;
  27. #else
  28. typedef unsigned long gpoint_count;
  29. #endif
  30.  
  31. /* this is plain C but in sync with v.in.lidar */
  32. static void check_layers_not_equal(int primary, int secondary,
  33.                                    const char *primary_name,
  34.                                    const char *secondary_name)
  35. {
  36.     if (primary && primary == secondary)
  37.         G_fatal_error(_("Values of %s and %s are the same."
  38.                         " All categories would be stored only"
  39.                         " in layer number <%d>"), primary_name,
  40.                       secondary_name, primary);
  41. }
  42.  
  43. static void check_layers_in_list_not_equal(struct Option **options,
  44.                                            int *values, size_t size)
  45. {
  46.     size_t layer_index_1, layer_index_2;
  47.     for (layer_index_1 = 0; layer_index_1 < size; layer_index_1++) {
  48.         for (layer_index_2 = 0; layer_index_2 < size; layer_index_2++) {
  49.             if (layer_index_1 != layer_index_2) {
  50.                 check_layers_not_equal(values[layer_index_1],
  51.                                        values[layer_index_2],
  52.                                        options[layer_index_1]->key,
  53.                                        options[layer_index_2]->key);
  54.             }
  55.         }
  56.     }
  57. }
  58.  
  59. // modified by Pei JIA, 2018-02-22
  60. void pdal_point_to_grass(struct Map_info *output_vector,
  61.                          struct line_pnts *points, struct line_cats *cats,
  62.                          pdal::PointViewPtr point_view, pdal::PointId idx,
  63.                          struct GLidarLayers *layers, int cat)//,
  64.                          //pdal::Dimension::Id::Enum dim_to_use_as_z)
  65. {
  66.     Vect_reset_line(points);
  67.     Vect_reset_cats(cats);
  68.  
  69.     //using namespace pdal::Dimension::Id;
  70.     double x = point_view->getFieldAs<double>(pdal::Dimension::Id::X, idx);
  71.     double y = point_view->getFieldAs<double>(pdal::Dimension::Id::Y, idx);
  72.     double z = point_view->getFieldAs<double>(pdal::Dimension::Id::Z, idx);
  73.     //double z = point_view->getFieldAs<double>(dim_to_use_as_z, idx);
  74.  
  75.     /* TODO: optimize for case with no layers, by adding
  76.      * and if to skip all the other ifs */
  77.     if (layers->id_layer) {
  78.         Vect_cat_set(cats, layers->id_layer, cat);
  79.     }
  80.     if (layers->return_layer) {
  81.         int return_n = point_view->getFieldAs<int>(pdal::Dimension::Id::ReturnNumber, idx);
  82.         int n_returns = point_view->getFieldAs<int>(pdal::Dimension::Id::NumberOfReturns, idx);
  83.         int return_c = return_to_cat(return_n, n_returns);
  84.         Vect_cat_set(cats, layers->return_layer, return_c);
  85.     }
  86.     if (layers->class_layer) {
  87.         Vect_cat_set(cats, layers->class_layer,
  88.                      point_view->getFieldAs<int>(pdal::Dimension::Id::Classification, idx));
  89.     }
  90.     if (layers->rgb_layer) {
  91.         int red = point_view->getFieldAs<int>(pdal::Dimension::Id::Red, idx);
  92.         int green = point_view->getFieldAs<int>(pdal::Dimension::Id::Green, idx);
  93.         int blue = point_view->getFieldAs<int>(pdal::Dimension::Id::Blue, idx);
  94.         int rgb = red;
  95.         rgb = (rgb << 8) + green;
  96.         rgb = (rgb << 8) + blue;
  97.         rgb++;  /* cat 0 is not valid, add one */
  98.         Vect_cat_set(cats, layers->rgb_layer, rgb);
  99.     }
  100.  
  101.     Vect_append_point(points, x, y, z);
  102.     Vect_write_line(output_vector, GV_POINT, points, cats);
  103. }
  104.  
  105. int main(int argc, char *argv[])
  106. {
  107.     G_gisinit(argv[0]);
  108.  
  109.     GModule *module = G_define_module();
  110.     G_add_keyword(_("vector"));
  111.     G_add_keyword(_("import"));
  112.     G_add_keyword(_("LIDAR"));
  113.     module->description =
  114.         _("Converts LAS LiDAR point clouds to a GRASS vector map with PDAL.");
  115.  
  116.     Option *in_opt = G_define_standard_option(G_OPT_F_INPUT);
  117.     in_opt->label = _("LAS input file");
  118.     in_opt->description =
  119.         _("LiDAR input files in LAS format (*.las or *.laz)");
  120.  
  121.     Option *out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  122.  
  123.     Option *id_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
  124.     id_layer_opt->key = "id_layer";
  125.     id_layer_opt->label = _("Layer number to store generated point ID as category");
  126.     id_layer_opt->description = _("Set to 1 by default, use -c to not store it");
  127.     id_layer_opt->answer = NULL;
  128.     id_layer_opt->guisection = _("Categories");
  129.  
  130.     Option *return_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
  131.     return_layer_opt->key = "return_layer";
  132.     return_layer_opt->label =
  133.         _("Layer number to store return information as category");
  134.     return_layer_opt->description = _("Leave empty to not store it");
  135.     return_layer_opt->answer = NULL;
  136.     return_layer_opt->guisection = _("Categories");
  137.  
  138.     Option *class_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
  139.     class_layer_opt->key = "class_layer";
  140.     class_layer_opt->label =
  141.         _("Layer number to store class number as category");
  142.     class_layer_opt->description = _("Leave empty to not store it");
  143.     class_layer_opt->answer = NULL;
  144.     class_layer_opt->guisection = _("Categories");
  145.  
  146.     Option *rgb_layer_opt = G_define_standard_option(G_OPT_V_FIELD);
  147.     rgb_layer_opt->key = "rgb_layer";
  148.     rgb_layer_opt->label =
  149.         _("Layer number where RBG colors are stored as category");
  150.     rgb_layer_opt->description = _("Leave empty to not store it");
  151.     rgb_layer_opt->answer = NULL;
  152.     rgb_layer_opt->guisection = _("Categories");
  153.  
  154.     Option *spatial_opt = G_define_option();
  155.     spatial_opt->key = "spatial";
  156.     spatial_opt->type = TYPE_DOUBLE;
  157.     spatial_opt->multiple = NO;
  158.     spatial_opt->required = NO;
  159.     // TODO: does this require multiple or not?
  160.     spatial_opt->key_desc = "xmin,ymin,xmax,ymax";
  161.     spatial_opt->label = _("Import subregion only");
  162.     spatial_opt->description =
  163.         _("Format: xmin,ymin,xmax,ymax - usually W,S,E,N");
  164.     spatial_opt->guisection = _("Selection");
  165.  
  166.     Option *zrange_opt = G_define_option();
  167.     zrange_opt->key = "zrange";
  168.     zrange_opt->type = TYPE_DOUBLE;
  169.     zrange_opt->required = NO;
  170.     zrange_opt->key_desc = "min,max";
  171.     zrange_opt->description = _("Filter range for z data (min,max)");
  172.     zrange_opt->guisection = _("Selection");
  173.  
  174.     Option *filter_opt = G_define_option();
  175.     filter_opt->key = "return_filter";
  176.     filter_opt->type = TYPE_STRING;
  177.     filter_opt->required = NO;
  178.     filter_opt->label = _("Only import points of selected return type");
  179.     filter_opt->description = _("If not specified, all points are imported");
  180.     filter_opt->options = "first,last,mid";
  181.     filter_opt->guisection = _("Selection");
  182.  
  183.     Option *class_opt = G_define_option();
  184.     class_opt->key = "class_filter";
  185.     class_opt->type = TYPE_INTEGER;
  186.     class_opt->multiple = YES;
  187.     class_opt->required = NO;
  188.     class_opt->label = _("Only import points of selected class(es)");
  189.     class_opt->description = _("Input is comma separated integers. "
  190.                                "If not specified, all points are imported.");
  191.     class_opt->guisection = _("Selection");
  192.  
  193.     Flag *reproject_flag = G_define_flag();
  194.     reproject_flag->key = 'w';
  195.     reproject_flag->label =
  196.         _("Reproject to location's coordinate system if needed");
  197.     reproject_flag->description =
  198.         _("Reprojects input dataset to the coordinate system of"
  199.           " the GRASS location (by default only datasets with the"
  200.           " matching cordinate system can be imported");
  201.     reproject_flag->guisection = _("Projection");
  202.  
  203.     Flag *over_flag = G_define_flag();
  204.     over_flag->key = 'o';
  205.     over_flag->label =
  206.         _("Override projection check (use current location's projection)");
  207.     over_flag->description =
  208.         _("Assume that the dataset has same projection as the current location");
  209.     over_flag->guisection = _("Projection");
  210.  
  211.     // TODO: from the API it seems that also prj file path and proj string will work
  212.     Option *input_srs_opt = G_define_option();
  213.     input_srs_opt->key = "input_srs";
  214.     input_srs_opt->type = TYPE_STRING;
  215.     input_srs_opt->required = NO;
  216.     input_srs_opt->label =
  217.             _("Input dataset projection (WKT or EPSG, e.g. EPSG:4326)");
  218.     input_srs_opt->description =
  219.             _("Override input dataset coordinate system using EPSG code"
  220.               " or WKT definition");
  221.     input_srs_opt->guisection = _("Projection");
  222.  
  223.     Option *max_ground_window_opt = G_define_option();
  224.     max_ground_window_opt->key = "max_ground_window_size";
  225.     max_ground_window_opt->type = TYPE_DOUBLE;
  226.     max_ground_window_opt->required = NO;
  227.     max_ground_window_opt->answer = "33";
  228.     max_ground_window_opt->description =
  229.         _("Maximum window size for ground filter");
  230.     max_ground_window_opt->guisection = _("Ground filter");
  231.  
  232.     Option *ground_slope_opt = G_define_option();
  233.     ground_slope_opt->key = "ground_slope";
  234.     ground_slope_opt->type = TYPE_DOUBLE;
  235.     ground_slope_opt->required = NO;
  236.     ground_slope_opt->answer = "1.0";
  237.     ground_slope_opt->description = _("Slope for ground filter");
  238.     ground_slope_opt->guisection = _("Ground filter");
  239.  
  240.     Option *max_ground_distance_opt = G_define_option();
  241.     max_ground_distance_opt->key = "max_ground_distance";
  242.     max_ground_distance_opt->type = TYPE_DOUBLE;
  243.     max_ground_distance_opt->required = NO;
  244.     max_ground_distance_opt->answer = "2.5";
  245.     max_ground_distance_opt->description =
  246.         _("Maximum distance for ground filter");
  247.     max_ground_distance_opt->guisection = _("Ground filter");
  248.  
  249.     Option *init_ground_distance_opt = G_define_option();
  250.     init_ground_distance_opt->key = "initial_ground_distance";
  251.     init_ground_distance_opt->type = TYPE_DOUBLE;
  252.     init_ground_distance_opt->required = NO;
  253.     init_ground_distance_opt->answer = "0.15";
  254.     init_ground_distance_opt->description =
  255.         _("Initial distance for ground filter");
  256.     init_ground_distance_opt->guisection = _("Ground filter");
  257.  
  258.     Option *ground_cell_size_opt = G_define_option();
  259.     ground_cell_size_opt->key = "ground_cell_size";
  260.     ground_cell_size_opt->type = TYPE_DOUBLE;
  261.     ground_cell_size_opt->required = NO;
  262.     ground_cell_size_opt->answer = "1";
  263.     ground_cell_size_opt->description =
  264.         _("Initial distance for ground filter");
  265.     ground_cell_size_opt->guisection = _("Ground filter");
  266.  
  267.     Flag *nocats_flag = G_define_flag();
  268.     nocats_flag->key = 'c';
  269.     nocats_flag->label =
  270.         _("Do not automatically add unique ID as category to each point");
  271.     nocats_flag->description =
  272.         _("Create only requested layers and categories");
  273.     /* v.in.lidar has this in Speed but we don't have it here */
  274.     nocats_flag->guisection = _("Categories");
  275.  
  276.     Flag *region_flag = G_define_flag();
  277.     region_flag->key = 'r';
  278.     region_flag->guisection = _("Selection");
  279.     region_flag->description = _("Limit import to the current region");
  280.  
  281.     Flag *extract_ground_flag = G_define_flag();
  282.     extract_ground_flag->key = 'j';
  283.     extract_ground_flag->label =
  284.         _("Classify and extract ground points");
  285.     extract_ground_flag->description =
  286.         _("This assignes class 2 to the groud points");
  287.     extract_ground_flag->guisection = _("Ground filter");
  288.  
  289.     // TODO: by inverting class filter and choosing 2 we can select non-groud points
  290.     // this can be done as a separate flag (generally useful?)
  291.     // or this flag can be changed (only ground is classified anyway)
  292.     // and it would Classify ground and extract non-ground
  293.     // probably better if only one step is required to get ground and non-ground
  294.     Flag *classify_ground_flag = G_define_flag();
  295.     classify_ground_flag->key = 'k';
  296.     classify_ground_flag->description = _("Classify ground points");
  297.     classify_ground_flag->guisection = _("Ground filter");
  298.  
  299.     Flag *height_filter_flag = G_define_flag();
  300.     height_filter_flag->key = 'h';
  301.     height_filter_flag->label =
  302.         _("Compute height for points as a difference from ground");
  303.     height_filter_flag->description =
  304.         _("This requires points to have class 2");
  305.     height_filter_flag->guisection = _("Transform");
  306.  
  307.     Flag *approx_ground_flag = G_define_flag();
  308.     approx_ground_flag->key = 'm';
  309.     approx_ground_flag->description =
  310.         _("Use approximate algorithm in ground filter");
  311.     approx_ground_flag->guisection = _("Ground filter");
  312.  
  313.     G_option_exclusive(spatial_opt, region_flag, NULL);
  314.     G_option_exclusive(reproject_flag, over_flag, NULL);
  315.     G_option_exclusive(extract_ground_flag, classify_ground_flag, NULL);
  316.     G_option_exclusive(nocats_flag, id_layer_opt, NULL);
  317.     G_option_requires(return_layer_opt, id_layer_opt, nocats_flag, NULL);
  318.     G_option_requires(class_layer_opt, id_layer_opt, nocats_flag, NULL);
  319.     G_option_requires(rgb_layer_opt, id_layer_opt, nocats_flag, NULL);
  320.  
  321.     if (G_parser(argc, argv))
  322.         return EXIT_FAILURE;
  323.  
  324.     if (access(in_opt->answer, F_OK) != 0) {
  325.         G_fatal_error(_("Input file <%s> does not exist"), in_opt->answer);
  326.     }
  327.  
  328.     // we use full qualification because the dim ns contains too general names
  329.     //pdal::Dimension::Id::Enum dim_to_use_as_z = pdal::Dimension::Id::Z;
  330.  
  331.     struct GLidarLayers layers;
  332.     GLidarLayers_set_no_layers(&layers);
  333.     layers.id_layer = 1;
  334.     if (id_layer_opt->answer && id_layer_opt->answer[0] != '\0')
  335.         layers.id_layer = std::stoi(id_layer_opt->answer);
  336.     if (return_layer_opt->answer && return_layer_opt->answer[0] != '\0')
  337.         layers.return_layer = std::stoi(return_layer_opt->answer);
  338.     if (class_layer_opt->answer && class_layer_opt->answer[0] != '\0')
  339.         layers.class_layer = std::stoi(class_layer_opt->answer);
  340.     if (rgb_layer_opt->answer && rgb_layer_opt->answer[0] != '\0')
  341.         layers.rgb_layer = std::stoi(rgb_layer_opt->answer);
  342.  
  343.     if (nocats_flag->answer) {
  344.         layers.id_layer = 0;
  345.     }
  346.  
  347.     /* this is plain C but in sync with v.in.lidar */
  348.     Option *layer_options[4] = {id_layer_opt, return_layer_opt,
  349.                                 class_layer_opt, rgb_layer_opt};
  350.     int layer_values[4] = {layers.id_layer, layers.return_layer,
  351.                            layers.class_layer, layers.rgb_layer};
  352.     check_layers_in_list_not_equal(layer_options, layer_values, 4);
  353.  
  354.     if (layers.id_layer)
  355.         G_verbose_message(_("Storing generated point IDs as categories"
  356.                             " in the layer <%d>, consequently no more"
  357.                             " than %d points can be imported"),
  358.                           layers.id_layer, GV_CAT_MAX);
  359.  
  360.     double xmin = 0;
  361.     double ymin = 0;
  362.     double xmax = 0;
  363.     double ymax = 0;
  364.     bool use_spatial_filter = false;
  365.     if (spatial_opt->answer)
  366.         use_spatial_filter = spatial_filter_from_option(spatial_opt,
  367.                                                         &xmin, &ymin,
  368.                                                         &xmax, &ymax);
  369.     else if (region_flag->answer)
  370.         use_spatial_filter = spatial_filter_from_current_region(&xmin,
  371.                                                                 &ymin,
  372.                                                                 &xmax,
  373.                                                                 &ymax);
  374.  
  375.     double zrange_min, zrange_max;
  376.     bool use_zrange = zrange_filter_from_option(zrange_opt, &zrange_min,
  377.                                                 &zrange_max);
  378.     struct ReturnFilter return_filter_struct;
  379.     bool use_return_filter =
  380.         return_filter_create_from_string(&return_filter_struct,
  381.                                          filter_opt->answer);
  382.     struct ClassFilter class_filter;
  383.     bool use_class_filter =
  384.         class_filter_create_from_strings(&class_filter, class_opt->answers);
  385.  
  386.     pdal::StageFactory factory;
  387.     std::string pdal_read_driver = factory.inferReaderDriver(in_opt->answer);
  388.     if (pdal_read_driver.empty())
  389.         G_fatal_error("Cannot determine input file type of <%s>",
  390.                       in_opt->answer);
  391.  
  392.     pdal::Option las_opt("filename", in_opt->answer);
  393.     pdal::Options las_opts;
  394.     las_opts.add(las_opt);
  395.     // TODO: free reader
  396.     // using plain pointer because we need to keep the last stage pointer
  397.     pdal::Stage * reader = factory.createStage(pdal_read_driver);
  398.     if (!reader)
  399.         G_fatal_error("PDAL reader creation failed, a wrong format of <%s>",
  400.                       in_opt->answer);
  401.     reader->setOptions(las_opts);
  402.  
  403.     pdal::Stage * last_stage = reader;
  404.     pdal::ReprojectionFilter reprojection_filter;
  405.  
  406.     // we reproject when requested regardless the input projection
  407.     if (reproject_flag->answer) {
  408.         G_message(_("Reprojecting the input to the location projection"));
  409.         char *proj_wkt = location_projection_as_wkt(false);
  410.         pdal::Options o4;
  411.         // TODO: try catch for user input error
  412.         if (input_srs_opt->answer)
  413.             o4.add<std::string>("in_srs", input_srs_opt->answer);
  414.         o4.add<std::string>("out_srs", proj_wkt);
  415.         reprojection_filter.setOptions(o4);
  416.         reprojection_filter.setInput(*reader);
  417.         last_stage = &reprojection_filter;
  418.     }
  419.  
  420.     if (extract_ground_flag->answer || classify_ground_flag->answer) {
  421.         if (extract_ground_flag->answer)
  422.             G_message(_("Extracting ground points"));
  423.         if (classify_ground_flag->answer)
  424.             G_message(_("Classifying ground points"));
  425.         pdal::Options groundOptions;
  426.         groundOptions.add<double>("max_window_size",
  427.                                   atof(max_ground_window_opt->answer));
  428.         groundOptions.add<double>("slope",
  429.                                   atof(ground_slope_opt->answer));
  430.         groundOptions.add<double>("max_distance",
  431.                                   atof(max_ground_distance_opt->answer));
  432.         groundOptions.add<double>("initial_distance",
  433.                                   atof(init_ground_distance_opt->answer));
  434.         groundOptions.add<double>("cell_size",
  435.                                   atof(ground_cell_size_opt->answer));
  436.         groundOptions.add<bool>("classify",
  437.                                 classify_ground_flag->answer);
  438.         groundOptions.add<bool>("extract",
  439.                                 extract_ground_flag->answer);
  440.         groundOptions.add<bool>("approximate",
  441.                                 approx_ground_flag->answer);
  442.         groundOptions.add<bool>("debug", false);
  443.         groundOptions.add<uint32_t>("verbose", 0);
  444.  
  445.         // TODO: free this or change pointer type to shared
  446.         pdal::Stage * ground_stage(factory.createStage("filters.ground"));
  447.         if (!ground_stage)
  448.             G_fatal_error(_("Ground filter is not available"
  449.                             " (PDAL probably compiled without PCL)"));
  450.         ground_stage->setOptions(groundOptions);
  451.         ground_stage->setInput(*last_stage);
  452.         last_stage = ground_stage;
  453.     }
  454.  
  455.     if (height_filter_flag->answer) {
  456.         // TODO: we should test with if (point_view->hasDim(Id::Classification))
  457.         // but we don't have the info yet
  458.         // TODO: free this or change pointer type to shared
  459.         pdal::Stage * height_stage(factory.createStage("filters.height"));
  460.         if (!height_stage)
  461.             G_fatal_error(_("Height above ground filter is not available"
  462.                             " (PDAL probably compiled without PCL)"));
  463.         height_stage->setInput(*last_stage);
  464.         last_stage = height_stage;
  465.     }
  466.  
  467.     pdal::PointTable point_table;
  468.     last_stage->prepare(point_table);
  469.  
  470.     // getting projection is possible only after prepare
  471.     if (over_flag->answer) {
  472.         G_important_message(_("Overriding projection check and assuming"
  473.                               " that the projection of input matches"
  474.                               " the location projection"));
  475.     }
  476.     else if (!reproject_flag->answer) {
  477.         pdal::SpatialReference spatial_reference = reader->getSpatialReference();
  478.         if (spatial_reference.empty())
  479.             G_fatal_error(_("The input dataset has undefined projection"));
  480.         std::string dataset_wkt =
  481.             spatial_reference.
  482.             //getWKT(pdal::SpatialReference::eHorizontalOnly);
  483.             getWKT();
  484.         bool proj_match = is_wkt_projection_same_as_loc(dataset_wkt.c_str());
  485.         if (!proj_match)
  486.             wkt_projection_mismatch_report(dataset_wkt.c_str());
  487.     }
  488.  
  489.     G_important_message(_("Running PDAL algorithms..."));
  490.     pdal::PointViewSet point_view_set = last_stage->execute(point_table);
  491.     pdal::PointViewPtr point_view = *point_view_set.begin();
  492.  
  493.     // TODO: test also z
  494.     // TODO: the falses for filters should be perhaps fatal error
  495.     // (bad input) or warning if filter was requested by the user
  496.  
  497.     // update layers we are writing based on what is in the data
  498.     // update usage of our filters as well
  499.     if (point_view->hasDim(pdal::Dimension::Id::ReturnNumber) &&
  500.         point_view->hasDim(pdal::Dimension::Id::NumberOfReturns)) {
  501.         use_return_filter = true;
  502.     }
  503.     else {
  504.         if (layers.return_layer) {
  505.             layers.return_layer = 0;
  506.             G_warning(_("Cannot store return information because the"
  507.                         " input does not have a return dimensions"));
  508.         }
  509.         use_return_filter = false;
  510.     }
  511.  
  512.     if (point_view->hasDim(pdal::Dimension::Id::Classification)) {
  513.         use_class_filter = true;
  514.     }
  515.     else {
  516.         if (layers.class_layer) {
  517.             layers.class_layer = 0;
  518.             G_warning(_("Cannot store class because the input"
  519.                         " does not have a classification dimension"));
  520.         }
  521.         use_class_filter = false;
  522.     }
  523.  
  524.     if (!(point_view->hasDim(pdal::Dimension::Id::Red) &&
  525.           point_view->hasDim(pdal::Dimension::Id::Green) &&
  526.           point_view->hasDim(pdal::Dimension::Id::Blue))) {
  527.         if (layers.rgb_layer) {
  528.             layers.rgb_layer = 0;
  529.             G_warning(_("Cannot store RGB colors because the input"
  530.                         " does not have a RGB dimensions"));
  531.         }
  532.     }
  533.  
  534.     G_important_message(_("Scanning points..."));
  535.     struct Map_info output_vector;
  536.  
  537.     // the overwrite warning comes quite late in the execution
  538.     // but that's good enough
  539.     if (Vect_open_new(&output_vector, out_opt->answer, 1) < 0)
  540.         G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
  541.     Vect_hist_command(&output_vector);
  542.  
  543.     // height is stored as a new attribute
  544.     if (height_filter_flag->answer) {
  545.         //dim_to_use_as_z = point_view->layout()->findDim("Height");
  546.         //if (dim_to_use_as_z == pdal::Dimension::Id::Unknown)
  547.         if(point_view->layout()->findDim("Height") == pdal::Dimension::Id::Unknown)
  548.             G_fatal_error(_("Cannot identify the height dimension"
  549.                             " (probably something changed in PDAL)"));
  550.     }
  551.  
  552.     // this is just for sure, we test the individual dimensions before
  553.     // TODO: should we test Z explicitly as well?
  554.     //if (!point_view->hasDim(dim_to_use_as_z))
  555.     if (!point_view->hasDim(pdal::Dimension::Id::Z))
  556.         G_fatal_error(_("Dataset doesn't have requested dimension '%s'"
  557.                         " with ID %d (possibly a programming error)"),
  558.                       //pdal::Dimension::name(dim_to_use_as_z).c_str(),
  559.                       //dim_to_use_as_z);
  560.                       pdal::Dimension::name(pdal::Dimension::Id::Z).c_str(),
  561.                       pdal::Dimension::Id::Z);
  562.  
  563.     struct line_pnts *points = Vect_new_line_struct();
  564.     struct line_cats *cats = Vect_new_cats_struct();
  565.  
  566.     gpoint_count n_outside = 0;
  567.     gpoint_count zrange_filtered = 0;
  568.     gpoint_count n_filtered = 0;
  569.     gpoint_count n_class_filtered = 0;
  570.  
  571.     int cat = 1;
  572.     bool cat_max_reached = false;
  573.  
  574.     for (pdal::PointId idx = 0; idx < point_view->size(); ++idx) {
  575.         // TODO: avoid duplication of reading the attributes here and when writing if needed
  576.         double x = point_view->getFieldAs<double>(pdal::Dimension::Id::X, idx);
  577.         double y = point_view->getFieldAs<double>(pdal::Dimension::Id::Y, idx);
  578.         double z = point_view->getFieldAs<double>(pdal::Dimension::Id::Z, idx);
  579.         //double z = point_view->getFieldAs<double>(dim_to_use_as_z, idx);
  580.  
  581.         if (use_spatial_filter) {
  582.             if (x < xmin || x > xmax || y < ymin || y > ymax) {
  583.                 n_outside++;
  584.                 continue;
  585.             }
  586.         }
  587.         if (use_zrange) {
  588.             if (z < zrange_min || z > zrange_max) {
  589.                 zrange_filtered++;
  590.                 continue;
  591.             }
  592.         }
  593.         if (use_return_filter) {
  594.             int return_n =
  595.                 point_view->getFieldAs<int>(pdal::Dimension::Id::ReturnNumber, idx);
  596.             int n_returns =
  597.                 point_view->getFieldAs<int>(pdal::Dimension::Id::NumberOfReturns, idx);
  598.             if (return_filter_is_out
  599.                 (&return_filter_struct, return_n, n_returns)) {
  600.                 n_filtered++;
  601.                 continue;
  602.             }
  603.         }
  604.         if (use_class_filter) {
  605.             int point_class =
  606.                 point_view->getFieldAs<int>(pdal::Dimension::Id::Classification, idx);
  607.             if (class_filter_is_out(&class_filter, point_class)) {
  608.                 n_class_filtered++;
  609.                 continue;
  610.             }
  611.         }
  612.         pdal_point_to_grass(&output_vector, points, cats, point_view,
  613.                             //idx, &layers, cat, dim_to_use_as_z);
  614.                             idx, &layers, cat);
  615.         if (layers.id_layer) {
  616.             // TODO: perhaps it would be better to use the max cat afterwards
  617.             if (cat == GV_CAT_MAX) {
  618.                 cat_max_reached = true;
  619.                 break;
  620.             }
  621.             cat++;
  622.         }
  623.     }
  624.     // not building topology by default
  625.     Vect_close(&output_vector);
  626. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement