1 #ifndef boxm2_block_h_
2 #define boxm2_block_h_
3 //:
4 // \file
5 // \brief boxm2_block models the building block of a boxm2_scene
6 //
7 // boxm2_block is a fixed grid of octtrees, and composes a boxm2_scene.
8 // like boxm2_data, a boxm2_block will construct itself from a simple, flat
9 // char stream, allocating no extra memory for itself. This flat char stream
10 // will then be owned by the block, and the block will destroy it upon calling
11 // its destructor.
12 //
13 // \author Andrew Miller
14 // \date 26 Oct 2010
15 //
16 #include <iostream>
17 #include <iosfwd>
18 #include <boxm2/boxm2_block_metadata.h>
19 #include <boxm2/basic/boxm2_block_id.h>
20 #include <boxm2/basic/boxm2_array_1d.h>
21 #include <boxm2/basic/boxm2_array_2d.h>
22 #include <boxm2/basic/boxm2_array_3d.h>
23 #include <vnl/vnl_vector_fixed.h>
24 #include <vgl/vgl_vector_3d.h>
25 #ifdef _MSC_VER
26 # include <vcl_msvc_warnings.h>
27 #endif
28
29 //smart pointer stuff
30 #include <vbl/vbl_ref_count.h>
31 #include <vbl/vbl_smart_ptr.h>
32 struct cell_info{
cell_infocell_info33 cell_info(): depth_(0),data_index_(0), side_length_(0.0){}
34 vgl_point_3d<double> cell_center_;
35 unsigned depth_;
36 unsigned data_index_;
37 double side_length_;
38 };
39
40 class boxm2_block : public vbl_ref_count
41 {
42 public:
43 typedef vnl_vector_fixed<unsigned short, 2> ushort2; //defines a block pointer
44 typedef vnl_vector_fixed<unsigned char, 16> uchar16; //defines a bit tree
45 typedef unsigned short ushort;
46
47 public:
48
49 //: only available constructor - from directory and block_id
50 boxm2_block(boxm2_block_id const& id, char* buffer);
51
52 boxm2_block(boxm2_block_id const& id, boxm2_block_metadata const& data, char* buffer);
53
54 //: creates empty block from metadata
55 boxm2_block(boxm2_block_metadata const& data);
56
57 //: initializes empty block from metadata
58 bool init_empty_block(boxm2_block_metadata const& data);
59
60 //: default destructor
~boxm2_block()61 ~boxm2_block() override { if (buffer_) delete[] buffer_; }
62
63 //: all IO manipulates char buffers
64 bool b_read(char* buffer);
65 bool b_write(char* buffer);
66
67 //: filename for all block files stored by boxm2_scenes
filename()68 std::string filename() const { return "block.bin"; }
69
70 //: accessors
block_id()71 boxm2_block_id& block_id() { return block_id_; } //somehow make this a const return..
buffer()72 char* buffer() { return buffer_; }
73 // User has only write access to a copy of the current trees via trees_copy(); Use the set_trees method to put them back in the block
74 // this way, n_cells_ will always remain up to date.
trees()75 const boxm2_array_3d<uchar16>& trees() { return trees_; }
sub_block_dim()76 vgl_vector_3d<double>& sub_block_dim() { return sub_block_dim_; }
sub_block_num()77 vgl_vector_3d<unsigned>& sub_block_num() { return sub_block_num_; }
num_buffers()78 int num_buffers() const { return 1; }
tree_buff_length()79 int tree_buff_length() const { return (int)trees_.size(); }
init_level()80 int init_level() const { return init_level_; }
max_level()81 int max_level() const { return max_level_; }
max_mb()82 int max_mb() const { return max_mb_; }
byte_count()83 long byte_count() const { return byte_count_; }
num_cells()84 unsigned num_cells() const { return n_cells_; }
local_origin()85 vgl_point_3d<double> local_origin() const { return local_origin_;}
86 //: mutators
set_block_id(boxm2_block_id const & id)87 void set_block_id(boxm2_block_id const& id) { block_id_ = id; }
set_init_level(int level)88 void set_init_level(int level) { init_level_ = level; }
set_max_level(int level)89 void set_max_level(int level) { max_level_ = level; }
set_max_mb(int mb)90 void set_max_mb(int mb) { max_mb_ = mb; }
set_byte_count(long bc)91 void set_byte_count(long bc) { byte_count_ = bc; }
92
93 //: calculate the number of bytes a block will be given three parameters
94 long calc_byte_count(int num_buffers, int trees_per_buffer, int num_trees);
95
96 //: regardless of the way the instance is constructed, enable write
enable_write()97 void enable_write() { read_only_ = false; }
98 // Sets the trees of the current block
set_trees(const boxm2_array_3d<uchar16> & that)99 void set_trees(const boxm2_array_3d<uchar16>& that){
100 if(that.get_row1_count()!=this->trees_.get_row1_count() || that.get_row2_count()!=this->trees_.get_row2_count() || that.get_row3_count()!=this->trees_.get_row3_count()){
101 std::cout<<"Cannot assign tree array to block id "<<this->block_id_<<" ; sizes mismatch!"<<std::endl;
102 return;
103 }
104 std::memcpy(this->trees_.data_block() , that.data_block(),that.size() * 16);
105 n_cells_ = this->recompute_num_cells();
106 }
107 // Returns a deep copy of the current tree array. The caller will take ownership; Use this method to modify the current tree array
trees_copy()108 boxm2_array_3d<uchar16> trees_copy(){
109 uchar16 * copy_buff = new uchar16[trees_.size()];
110 std::memcpy(copy_buff, this->trees_.data_block() ,trees_.size() * 16);
111 return boxm2_array_3d<uchar16>(trees_.get_row1_count(),trees_.get_row2_count(),trees_.get_row3_count(),copy_buff);
112
113 }
read_only()114 bool read_only() const { return read_only_; }
115
116 //: construct the bounding box for the block in scene coordinates
117 vgl_box_3d<double> bounding_box_global() const;
118
119 /////
120 //: Global point methods. All test if the specified global point
121 // is inside *this block and produce coordinates and indices, returning true.
122 // If the point is not inside the block, the methods return false.
123 //
124 //: if the block contains the global_pt, compute the local real coordinates of the sub_block (tree)
125 bool contains(vgl_point_3d<double> const& global_pt, vgl_point_3d<double>& local_pt) const;
126 //: if the block contains the global_pt, compute the integer local coordinates of the sub_block (tree)
127 bool contains(vgl_point_3d<double> const& global_pt, vgl_point_3d<int>& local_pt) const;
128
129 //: retrieve local tree coordinates for global_pt and the coords for the cell containing the global point
130 bool contains(vgl_point_3d<double> const& global_pt, vgl_point_3d<double>& local_tree_coords,
131 vgl_point_3d<double>& cell_center, double& side_length) const;
132
133 //: compute the data index for the cell containing the pt, also return cell octree depth and cell side length
134 bool data_index(vgl_point_3d<double> const& global_pt, unsigned& index, unsigned& depth, double& side_length) const;
135
136 //: just get the data index
137 bool data_index(vgl_point_3d<double> const& global_pt, unsigned& index) const;
138
139 //: retrieve a vector of cell centers and other info inside the specified bounding box, both in global world coordinates
140 std::vector<cell_info> cells_in_box(vgl_box_3d<double> const& global_box);
141
142 // find neigboring sub_block cell centers within a specified distance from probe, including the cell containing the probe
143 std::vector<vgl_point_3d<double> > sub_block_neighbors(vgl_point_3d<double> const& probe, double distance) const;
144
145 //: retrieve neighborhood of probe consisting of leaf cells. If relative_distance is true then the neighborhood distance
146 // is scaled according to the size of the cell containing the probe. Otherwise the distance is absolute, e.g. meters.
147 void leaf_neighbors(vgl_point_3d<double> const& probe, double distance, std::vector<vgl_point_3d<double> >& nbrs,
148 std::vector<double>& nbr_edge_lengths, std::vector<unsigned>& data_indices, bool relative_distance = true) const;
149 /////
150 //=== sub_block intersection methods ====//
151 ////
152 std::vector<vgl_point_3d<int> > sub_blocks_intersect_box(vgl_box_3d<double> const& box) const;
153 ////
154 private:
155 unsigned recompute_num_cells();
156 //: unique block id (currently 3D address)
157 boxm2_block_id block_id_;
158
159 //: byte buffer
160 char* buffer_;
161
162 //: number of bytes this block takes up (on disk and ram)
163 long byte_count_;
164
165 //: high level arrays store sub block information
166 boxm2_array_3d<uchar16> trees_;
167
168 //: World dimensions of a block .e.g 1 meter x 1 meter x 1 meter
169 vgl_vector_3d<double> sub_block_dim_;
170 vgl_vector_3d<unsigned> sub_block_num_;
171 vgl_point_3d<double> local_origin_;
172
173 //: info about block's trees
174 int init_level_; //each sub_blocks's init level (default 1)
175 int max_level_; //each sub_blocks's max_level (default 4)
176 int max_mb_; //each total block mb
177 unsigned n_cells_;
178 bool read_only_; // if the block existed already on the disc, do not write it back
179
180 short version_;
181 };
182
183
184 //: Smart_Pointer typedef for boxm2_block
185 typedef vbl_smart_ptr<boxm2_block> boxm2_block_sptr;
186
187 //: output stream
188 std::ostream& operator <<(std::ostream &s, boxm2_block& block);
189
190 //: write to xml file
191 //void x_write(std::ostream &os, boxm2_block& scene, std::string name);
192
193 //: Binary write boxm_update_bit_scene_manager scene to stream
194 void vsl_b_write(vsl_b_ostream& os, boxm2_block const& scene);
195 void vsl_b_write(vsl_b_ostream& os, const boxm2_block* &p);
196 void vsl_b_write(vsl_b_ostream& os, boxm2_block_sptr& sptr);
197 void vsl_b_write(vsl_b_ostream& os, boxm2_block_sptr const& sptr);
198
199 //: Binary load boxm_update_bit_scene_manager scene from stream.
200 void vsl_b_read(vsl_b_istream& is, boxm2_block &scene);
201 void vsl_b_read(vsl_b_istream& is, boxm2_block* p);
202 void vsl_b_read(vsl_b_istream& is, boxm2_block_sptr& sptr);
203 void vsl_b_read(vsl_b_istream& is, boxm2_block_sptr const& sptr);
204
205 #endif // boxm2_block_h_
206