55//  Author: Thomas Lowe
66#include  " raylib/extraction/rayclusters.h" 
77#include  " raylib/extraction/rayforest.h" 
8+ #include  " raylib/extraction/rayleaves.h" 
89#include  " raylib/extraction/rayterrain.h" 
910#include  " raylib/extraction/raytrees.h" 
1011#include  " raylib/extraction/raytrunks.h" 
11- #include  " raylib/extraction/rayleaves.h" 
1212#include  " raylib/raycloud.h" 
1313#include  " raylib/rayforestgen.h" 
1414#include  " raylib/rayforeststructure.h" 
@@ -25,7 +25,8 @@ static std::string extract_type;
2525
2626void  usage (int  exit_code = 1 )
2727{
28-   const  bool  none = extract_type != " terrain"   && extract_type != " trunks"   && extract_type != " forest"   && extract_type != " trees"   && extract_type != " leaves"  ;
28+   const  bool  none = extract_type != " terrain"   && extract_type != " trunks"   && extract_type != " forest"   &&
29+                     extract_type != " trees"   && extract_type != " leaves"  ;
2930  //  clang-format off
3031  std::cout << " Extract natural features into a text file or mesh file"   << std::endl;
3132  std::cout << " usage:"   << std::endl;
@@ -54,21 +55,22 @@ void usage(int exit_code = 1)
5455    std::cout << "                             --max_diameter 0.9   - (-m) maximum trunk diameter in segmenting trees"   << std::endl;
5556    std::cout << "                             --crop_length 1.0    - (-p) crops small branches to this distance from end"   << std::endl;
5657    std::cout << "                             --distance_limit 1   - (-d) maximum distance between neighbour points in a tree"   << std::endl;
57-     std::cout << "                             --height_min 2       - (-h) minimum height counted as a tree "   << std::endl;
58-     std::cout << "                             --min_radius 0.01     - (-r) minimum tree  radius to consider "   << std::endl;
58+     std::cout << "                             --height_min 2       - (-h) minimum height tree to reconstruct "   << std::endl;
59+     std::cout << "                             --radius_min 0         - (-r) minimum radius tree  to reconstruct "   << std::endl;
5960    std::cout << "                             --girth_height_ratio 0.12 - (-i) the amount up tree's height to estimate trunk girth"   << std::endl;
6061    std::cout << "                             --global_taper 0.024 - (-a) force a taper value (diameter per length) for trees under global_taper_factor of max tree height. Use 0 to estimate global taper from the data"   << std::endl;
6162    std::cout << "                             --global_taper_factor 0.3- (-o) 1 estimates same taper for whole scan, 0 is per-tree tapering. Like a soft cutoff at this amount of max tree height"   << std::endl;
6263    std::cout << "                             --gravity_factor 0.3 - (-f) larger values preference vertical trees"   << std::endl;
6364    std::cout << "                             --branch_segmentation- (-b) _segmented.ply is per branch segment"   << std::endl;
6465    std::cout << "                             --grid_width 10      - (-w) crops results assuming cloud has been gridded with given width"   << std::endl;
65-     std::cout << "                             --grid_origin 0,0,0 - location of origin within grid cell that overlaps it. Defaults to a cell-centre origin (at grid_width/2 in each axis) matching raysplit grid. 0,0,0 is for a vertex origin."   << std::endl;
6666    std::cout << "                             --use_rays           - (-u) use rays to reduce trunk radius overestimation in noisy cloud data"   << std::endl;
67-     std::cout << "                             (for internal constants -c -g -s see source file rayextract)"   << std::endl;
67+     std::cout << "                             (for internal constants -c -g -s -d  see source file rayextract)"   << std::endl;
6868  //  These are the internal parameters that I don't expose as they are 'advanced' only, you shouldn't need to adjust them
6969  //   std::cout << "                            --cylinder_length_to_width 4- (-c) how slender the cylinders are" << std::endl;
7070  //   std::cout << "                            --gap_ratio 0.016    - (-g) will split for lateral gaps at this multiple of branch length" << std::endl;
7171  //   std::cout << "                            --span_ratio 4.5     - (-s) will split when branch width spans this multiple of radius" << std::endl;
72+   //   std::cout << "                            --grid_origin 0,0    - (-d) location of grid corner (any of them) when grid_width used, use 0,0 for grid with vertex at 0,0. 
73+   //                                                                    Default is -grid_width/2,-grid_width/2 to match the grid in raysplit grid" << std::endl;
7274  }
7375  if  (extract_type == " leaves"   || none)
7476  {
@@ -94,33 +96,33 @@ int rayExtract(int argc, char *argv[])
9496  }
9597  ray::FileArgument cloud_file, mesh_file, trunks_file, trees_file, leaf_file;
9698  ray::TextArgument forest (" forest"  ), trees (" trees"  ), trunks (" trunks"  ), terrain (" terrain"  ), leaves (" leaves"  );
97- 
98-   ray::Vector3dArgument grid_origin;
99-   ray::OptionalKeyValueArgument grid_origin_option (" grid_origin"  , &grid_origin);
10099  ray::OptionalKeyValueArgument groundmesh_option (" ground"  , ' g'  , &mesh_file);
101100  ray::OptionalKeyValueArgument trunks_option (" trunks"  , ' t'  , &trunks_file);
102101  ray::DoubleArgument gradient (0.001 , 1000.0 , 1.0 ), global_taper (0.0 , 1.0 ), global_taper_factor (0.0 , 1.0 );
103102  ray::OptionalKeyValueArgument gradient_option (" gradient"  , ' g'  , &gradient);
104-   ray::OptionalFlagArgument exclude_rays (" exclude_rays"  , ' e'  ), segment_branches (" branch_segmentation"  , ' b'  ), stalks (" stalks"  , ' s'  ), use_rays (" use_rays"  , ' u'  );
103+   ray::OptionalFlagArgument exclude_rays (" exclude_rays"  , ' e'  ), segment_branches (" branch_segmentation"  , ' b'  ),
104+     stalks (" stalks"  , ' s'  ), use_rays (" use_rays"  , ' u'  );
105105  ray::DoubleArgument width (0.01 , 10.0 , 0.25 ), drop (0.001 , 1.0 ), max_gradient (0.01 , 5.0 ), min_gradient (0.01 , 5.0 );
106106
107107  ray::DoubleArgument max_diameter (0.01 , 100.0 ), distance_limit (0.01 , 10.0 ), height_min (0.01 , 1000.0 ),
108-     min_diameter (0.01 , 100.0 ), leaf_area (0.00001 , 1.0 , 0.002 ), leaf_droop (0.0 , 10.0 , 0.1 ), crop_length (0.01 , 100.0 );;
109-   ray::DoubleArgument girth_height_ratio (0.001 , 0.5 ), length_to_radius (0.01 , 10000.0 ), cylinder_length_to_width (0.1 , 20.0 ), gap_ratio (0.01 , 10.0 ),
110-     span_ratio (0.01 , 10.0 ), min_radius (0.01 , 100.0 );
111-   ray::DoubleArgument gravity_factor (0.0 , 100.0 ), grid_width (1.0 , 100000.0 ),
112-     grid_overlap (0.0 , 0.9 );
108+     radius_min (0.0 , 1000.0 ), min_diameter (0.01 , 100.0 ), leaf_area (0.00001 , 1.0 , 0.002 ), leaf_droop (0.0 , 10.0 , 0.1 ),
109+     crop_length (0.01 , 100.0 );
110+   ;
111+   ray::DoubleArgument girth_height_ratio (0.001 , 0.5 ), length_to_radius (0.01 , 10000.0 ),
112+     cylinder_length_to_width (0.1 , 20.0 ), gap_ratio (0.01 , 10.0 ), span_ratio (0.01 , 10.0 );
113+   ray::DoubleArgument gravity_factor (0.0 , 100.0 ), grid_width (1.0 , 100000.0 ), grid_overlap (0.0 , 0.9 );
114+   ray::Vector2dArgument grid_origin (-1e10 , 1e10 );
113115  ray::OptionalKeyValueArgument max_diameter_option (" max_diameter"  , ' m'  , &max_diameter);
114116  ray::OptionalKeyValueArgument crop_length_option (" crop_length"  , ' n'  , &crop_length);
115117  ray::OptionalKeyValueArgument distance_limit_option (" distance_limit"  , ' d'  , &distance_limit);
116118  ray::OptionalKeyValueArgument height_min_option (" height_min"  , ' h'  , &height_min);
119+   ray::OptionalKeyValueArgument radius_min_option (" radius_min"  , ' r'  , &radius_min);
117120  ray::OptionalKeyValueArgument girth_height_ratio_option (" girth_height_ratio"  , ' i'  , &girth_height_ratio);
118121  ray::OptionalKeyValueArgument cylinder_length_to_width_option (" cylinder_length_to_width"  , ' c'  ,
119122                                                                &cylinder_length_to_width);
120- 
121-   ray::OptionalKeyValueArgument min_radius_option (" min_radius"  , ' r'  , &min_radius);
122123  ray::OptionalKeyValueArgument gap_ratio_option (" gap_ratio"  , ' g'  , &gap_ratio);
123124  ray::OptionalKeyValueArgument span_ratio_option (" span_ratio"  , ' s'  , &span_ratio);
125+   ray::OptionalKeyValueArgument grid_origin_option (" grid_origin"  , ' d'  , &grid_origin);
124126  ray::OptionalKeyValueArgument gravity_factor_option (" gravity_factor"  , ' f'  , &gravity_factor);
125127  ray::OptionalKeyValueArgument grid_width_option (" grid_width"  , ' w'  , &grid_width);
126128  ray::OptionalKeyValueArgument global_taper_option (" global_taper"  , ' a'  , &global_taper);
@@ -142,11 +144,12 @@ int rayExtract(int argc, char *argv[])
142144    { &groundmesh_option, &trunks_option, &width_option, &smooth_option, &drop_option, &verbose });
143145  bool  extract_trees = ray::parseCommandLine (
144146    argc, argv, { &trees, &cloud_file, &mesh_file },
145-     { &max_diameter_option, &distance_limit_option, &height_min_option, &crop_length_option, &girth_height_ratio_option,
146-       &cylinder_length_to_width_option, &gap_ratio_option, &span_ratio_option, &gravity_factor_option,
147-       &segment_branches, &grid_width_option, &global_taper_option, &global_taper_factor_option, &use_rays, &verbose,
148-       &grid_origin_option, &min_radius_option });
149-   bool  extract_leaves = ray::parseCommandLine (argc, argv, { &leaves, &cloud_file, &trees_file }, { &leaf_option, &leaf_area_option, &leaf_droop_option, &stalks });
147+     { &max_diameter_option, &distance_limit_option, &height_min_option, &radius_min_option, &crop_length_option,
148+       &girth_height_ratio_option, &cylinder_length_to_width_option, &gap_ratio_option, &span_ratio_option,
149+       &grid_origin_option, &gravity_factor_option, &segment_branches, &grid_width_option, &global_taper_option,
150+       &global_taper_factor_option, &use_rays, &verbose });
151+   bool  extract_leaves = ray::parseCommandLine (argc, argv, { &leaves, &cloud_file, &trees_file },
152+                                               { &leaf_option, &leaf_area_option, &leaf_droop_option, &stalks });
150153
151154
152155  if  (!extract_trunks && !extract_forest && !extract_terrain && !extract_trees && !extract_leaves)
@@ -199,6 +202,10 @@ int rayExtract(int argc, char *argv[])
199202    {
200203      params.height_min  = height_min.value ();
201204    }
205+     if  (radius_min_option.isSet ())
206+     {
207+       params.radius_min  = radius_min.value ();
208+     }
202209    if  (crop_length_option.isSet ())
203210    {
204211      params.crop_length  = crop_length.value ();
@@ -226,6 +233,12 @@ int rayExtract(int argc, char *argv[])
226233    if  (grid_width_option.isSet ())
227234    {
228235      params.grid_width  = grid_width.value ();
236+       params.grid_origin  =
237+         -Eigen::Vector2d (grid_width.value (), grid_width.value ()) / 2.0 ;  //  the centred grid used by raysplit grid
238+     }
239+     if  (grid_origin_option.isSet ())
240+     {
241+       params.grid_origin  = grid_origin.value ();
229242    }
230243    if  (global_taper_option.isSet ())
231244    {
@@ -235,14 +248,6 @@ int rayExtract(int argc, char *argv[])
235248    {
236249      params.global_taper_factor  = global_taper_factor.value ();
237250    }
238-     if  (grid_origin_option.isSet ())
239-     {
240-       params.grid_origin  = grid_origin.value ();
241-     }
242-     if  (min_radius_option.isSet ())
243-     {
244-       params.min_radius  = min_radius.value ();
245-     }
246251    params.use_rays  = use_rays.isSet ();
247252    params.segment_branches  = segment_branches.isSet ();
248253
@@ -259,11 +264,15 @@ int rayExtract(int argc, char *argv[])
259264    ray::ForestStructure forest;
260265    if  (!forest.load (cloud_file.nameStub () + " _trees.txt"  ))
261266    {
262-       usage ();
267+       std::cerr << " Unable to load " 
268+                 << cloud_file.nameStub () +
269+                      " _trees.txt to generate tree mesh file, this could mean that there were no trees output" 
270+                 << std::endl;
271+       exit (true );
263272    }
264273    ray::Mesh tree_mesh;
265274    forest.generateSmoothMesh (tree_mesh, -1 , 1 , 1 , 1 );
266-     ray::writePlyMesh (cloud_file.nameStub () + " _trees_mesh.ply"  , tree_mesh, true );     
275+     ray::writePlyMesh (cloud_file.nameStub () + " _trees_mesh.ply"  , tree_mesh, true );
267276  }
268277  //  extract the tree locations from a larger, aerial view of a forest
269278  else  if  (extract_forest)
@@ -321,8 +330,8 @@ int rayExtract(int argc, char *argv[])
321330  }
322331  else  if  (extract_leaves)
323332  {
324-     ray::generateLeaves (cloud_file.nameStub (), trees_file.name (), leaf_file.name (), 
325-       leaf_area. value (),  leaf_droop.value (), stalks.isSet ());
333+     ray::generateLeaves (cloud_file.nameStub (), trees_file.name (), leaf_file.name (), leaf_area. value (), 
334+                          leaf_droop.value (), stalks.isSet ());
326335  }
327336  else 
328337  {
0 commit comments