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