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