5
5
// Author: Thomas Lowe
6
6
#include " raylib/extraction/rayclusters.h"
7
7
#include " raylib/extraction/rayforest.h"
8
+ #include " raylib/extraction/rayleaves.h"
8
9
#include " raylib/extraction/rayterrain.h"
9
10
#include " raylib/extraction/raytrees.h"
10
11
#include " raylib/extraction/raytrunks.h"
11
- #include " raylib/extraction/rayleaves.h"
12
12
#include " raylib/raycloud.h"
13
13
#include " raylib/rayforestgen.h"
14
14
#include " raylib/rayforeststructure.h"
@@ -25,7 +25,8 @@ static std::string extract_type;
25
25
26
26
void usage (int exit_code = 1 )
27
27
{
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" ;
29
30
// clang-format off
30
31
std::cout << " Extract natural features into a text file or mesh file" << std::endl;
31
32
std::cout << " usage:" << std::endl;
@@ -54,21 +55,22 @@ void usage(int exit_code = 1)
54
55
std::cout << " --max_diameter 0.9 - (-m) maximum trunk diameter in segmenting trees" << std::endl;
55
56
std::cout << " --crop_length 1.0 - (-p) crops small branches to this distance from end" << std::endl;
56
57
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;
59
60
std::cout << " --girth_height_ratio 0.12 - (-i) the amount up tree's height to estimate trunk girth" << std::endl;
60
61
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;
61
62
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;
62
63
std::cout << " --gravity_factor 0.3 - (-f) larger values preference vertical trees" << std::endl;
63
64
std::cout << " --branch_segmentation- (-b) _segmented.ply is per branch segment" << std::endl;
64
65
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;
66
66
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;
68
68
// These are the internal parameters that I don't expose as they are 'advanced' only, you shouldn't need to adjust them
69
69
// std::cout << " --cylinder_length_to_width 4- (-c) how slender the cylinders are" << std::endl;
70
70
// std::cout << " --gap_ratio 0.016 - (-g) will split for lateral gaps at this multiple of branch length" << std::endl;
71
71
// 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;
72
74
}
73
75
if (extract_type == " leaves" || none)
74
76
{
@@ -94,33 +96,33 @@ int rayExtract(int argc, char *argv[])
94
96
}
95
97
ray::FileArgument cloud_file, mesh_file, trunks_file, trees_file, leaf_file;
96
98
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);
100
99
ray::OptionalKeyValueArgument groundmesh_option (" ground" , ' g' , &mesh_file);
101
100
ray::OptionalKeyValueArgument trunks_option (" trunks" , ' t' , &trunks_file);
102
101
ray::DoubleArgument gradient (0.001 , 1000.0 , 1.0 ), global_taper (0.0 , 1.0 ), global_taper_factor (0.0 , 1.0 );
103
102
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' );
105
105
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 );
106
106
107
107
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 );
113
115
ray::OptionalKeyValueArgument max_diameter_option (" max_diameter" , ' m' , &max_diameter);
114
116
ray::OptionalKeyValueArgument crop_length_option (" crop_length" , ' n' , &crop_length);
115
117
ray::OptionalKeyValueArgument distance_limit_option (" distance_limit" , ' d' , &distance_limit);
116
118
ray::OptionalKeyValueArgument height_min_option (" height_min" , ' h' , &height_min);
119
+ ray::OptionalKeyValueArgument radius_min_option (" radius_min" , ' r' , &radius_min);
117
120
ray::OptionalKeyValueArgument girth_height_ratio_option (" girth_height_ratio" , ' i' , &girth_height_ratio);
118
121
ray::OptionalKeyValueArgument cylinder_length_to_width_option (" cylinder_length_to_width" , ' c' ,
119
122
&cylinder_length_to_width);
120
-
121
- ray::OptionalKeyValueArgument min_radius_option (" min_radius" , ' r' , &min_radius);
122
123
ray::OptionalKeyValueArgument gap_ratio_option (" gap_ratio" , ' g' , &gap_ratio);
123
124
ray::OptionalKeyValueArgument span_ratio_option (" span_ratio" , ' s' , &span_ratio);
125
+ ray::OptionalKeyValueArgument grid_origin_option (" grid_origin" , ' d' , &grid_origin);
124
126
ray::OptionalKeyValueArgument gravity_factor_option (" gravity_factor" , ' f' , &gravity_factor);
125
127
ray::OptionalKeyValueArgument grid_width_option (" grid_width" , ' w' , &grid_width);
126
128
ray::OptionalKeyValueArgument global_taper_option (" global_taper" , ' a' , &global_taper);
@@ -142,11 +144,12 @@ int rayExtract(int argc, char *argv[])
142
144
{ &groundmesh_option, &trunks_option, &width_option, &smooth_option, &drop_option, &verbose });
143
145
bool extract_trees = ray::parseCommandLine (
144
146
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 });
150
153
151
154
152
155
if (!extract_trunks && !extract_forest && !extract_terrain && !extract_trees && !extract_leaves)
@@ -199,6 +202,10 @@ int rayExtract(int argc, char *argv[])
199
202
{
200
203
params.height_min = height_min.value ();
201
204
}
205
+ if (radius_min_option.isSet ())
206
+ {
207
+ params.radius_min = radius_min.value ();
208
+ }
202
209
if (crop_length_option.isSet ())
203
210
{
204
211
params.crop_length = crop_length.value ();
@@ -226,6 +233,12 @@ int rayExtract(int argc, char *argv[])
226
233
if (grid_width_option.isSet ())
227
234
{
228
235
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 ();
229
242
}
230
243
if (global_taper_option.isSet ())
231
244
{
@@ -235,14 +248,6 @@ int rayExtract(int argc, char *argv[])
235
248
{
236
249
params.global_taper_factor = global_taper_factor.value ();
237
250
}
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
- }
246
251
params.use_rays = use_rays.isSet ();
247
252
params.segment_branches = segment_branches.isSet ();
248
253
@@ -259,11 +264,15 @@ int rayExtract(int argc, char *argv[])
259
264
ray::ForestStructure forest;
260
265
if (!forest.load (cloud_file.nameStub () + " _trees.txt" ))
261
266
{
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 );
263
272
}
264
273
ray::Mesh tree_mesh;
265
274
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 );
267
276
}
268
277
// extract the tree locations from a larger, aerial view of a forest
269
278
else if (extract_forest)
@@ -321,8 +330,8 @@ int rayExtract(int argc, char *argv[])
321
330
}
322
331
else if (extract_leaves)
323
332
{
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 ());
326
335
}
327
336
else
328
337
{
0 commit comments