1 /*****************************************************************************
2  *   Copyright (c) 2020, Hobu, Inc. (info@hobu.co)                           *
3  *                                                                           *
4  *   All rights reserved.                                                    *
5  *                                                                           *
6  *   This program is free software; you can redistribute it and/or modify    *
7  *   it under the terms of the GNU General Public License as published by    *
8  *   the Free Software Foundation; either version 3 of the License, or       *
9  *   (at your option) any later version.                                     *
10  *                                                                           *
11  ****************************************************************************/
12 
13 #pragma once
14 
15 #include <array>
16 #include <unordered_map>
17 
18 #include "../untwine/FileDimInfo.hpp"
19 #include "../untwine/GridKey.hpp"
20 #include "../untwine/Point.hpp"
21 #include "../untwine/VoxelKey.hpp"
22 
23 #include "OctantInfo.hpp"
24 
25 namespace untwine
26 {
27 namespace bu
28 {
29 
30 class VoxelInfo
31 {
32 public:
33     // This probably needs a data structure geared for sparse data as I *think* that many
34     // of our lookups will fail.
35     using Grid = std::unordered_map<GridKey, int>;
36 
VoxelInfo(const pdal::BOX3D & fullBounds,const VoxelKey & key)37     VoxelInfo(const pdal::BOX3D& fullBounds, const VoxelKey& key) :
38         m_fullBounds(fullBounds), m_octant(key)
39     {
40         //ABELL - This shouldn't be necessary. The key should be in the children
41         //  when they're pulled out of the queue.
42         for (int i = 0; i < 8; ++i)
43             m_children[i].setKey(key.child(i));
44 
45         int cells = (int)std::pow(2, key.level());
46         m_xWidth = (fullBounds.maxx - fullBounds.minx) / cells;
47         m_yWidth = (fullBounds.maxy - fullBounds.miny) / cells;
48         m_zWidth = (fullBounds.maxz - fullBounds.minz) / cells;
49         // Calculate the bounds of this voxel.
50         m_bounds.minx = fullBounds.minx + (key.x() * m_xWidth);
51         m_bounds.maxx = m_bounds.minx + m_xWidth;
52         m_bounds.miny = fullBounds.miny + (key.y() * m_yWidth);
53         m_bounds.maxy = m_bounds.miny + m_yWidth;
54         m_bounds.minz = fullBounds.minz + (key.z() * m_zWidth);
55         m_bounds.maxz = m_bounds.minz + m_zWidth;
56 
57         // Determine spacing between points.
58 //        m_spacing = minWidth() / 128.0;
59         m_spacing = maxWidth() / 128.0;
60 
61         // Make the spacing smaller than what we expect as the final spacing since we're
62         // going to select points from the grid for the parent.
63         if (key != VoxelKey(0, 0, 0, 0))
64             m_spacing *= 1.5;
65         m_squareSpacing = m_spacing * m_spacing;
66 
67         static const double sqrt3 = std::sqrt(3);
68         m_gridCellWidth = m_spacing / sqrt3;
69         m_gridXCount = (int)std::ceil((m_bounds.maxx - m_bounds.minx) / m_gridCellWidth);
70         m_gridYCount = (int)std::ceil((m_bounds.maxy - m_bounds.miny) / m_gridCellWidth);
71         m_gridZCount = (int)std::ceil((m_bounds.maxz - m_bounds.minz) / m_gridCellWidth);
72     }
73 
key() const74     VoxelKey key() const
75         { return m_octant.key(); }
76 
operator [](int dir)77     OctantInfo& operator[](int dir)
78         { return m_children[dir]; }
79 
octant()80     OctantInfo& octant()
81         { return m_octant; }
82 
numPoints() const83     size_t numPoints() const
84     {
85         size_t cnt = 0;
86         for (const OctantInfo& oi : m_children)
87             cnt += oi.numPoints();
88         return cnt;
89     }
90 
hasPoints() const91     bool hasPoints() const
92     {
93         for (const OctantInfo& oi : m_children)
94             if (oi.hasPoints())
95                 return true;
96         return false;
97     }
98 
spacing() const99     double spacing() const
100         { return m_spacing; }
101 
squareSpacing() const102     double squareSpacing() const
103         { return m_squareSpacing; }
104 
minWidth() const105     double minWidth() const
106         { return (std::min)((std::min)(m_xWidth, m_yWidth), m_zWidth); }
107 
maxWidth() const108     double maxWidth() const
109         { return (std::max)((std::max)(m_xWidth, m_yWidth), m_zWidth); }
110 
xWidth() const111     double xWidth() const
112         { return m_xWidth; }
113 
yWidth() const114     double yWidth() const
115         { return m_yWidth; }
116 
zWidth() const117     double zWidth() const
118         { return m_zWidth; }
119 
gridKey(const Point & p) const120     GridKey gridKey(const Point& p) const
121     {
122         double x = p.x() - m_bounds.minx;
123         double y = p.y() - m_bounds.miny;
124         double z = p.z() - m_bounds.minz;
125 
126         return GridKey((int)(x / m_gridCellWidth), (int)(y / m_gridCellWidth),
127             (int)(z / m_gridCellWidth));
128     }
129 
130     //ABELL - Really torn WRT making Grid its own thing.
131 
grid()132     Grid& grid()
133         { return m_grid; }
134 
gridXCount() const135     int gridXCount() const
136         { return m_gridXCount; }
137 
gridYCount() const138     int gridYCount() const
139         { return m_gridYCount; }
140 
gridZCount() const141     int gridZCount() const
142         { return m_gridZCount; }
143 
bounds() const144     pdal::BOX3D bounds() const
145         { return m_bounds; }
146 
147 private:
148     pdal::BOX3D m_fullBounds;
149     pdal::BOX3D m_bounds;
150     double m_xWidth;
151     double m_yWidth;
152     double m_zWidth;
153     double m_gridCellWidth;
154     int m_gridXCount;
155     int m_gridYCount;
156     int m_gridZCount;
157     std::array<OctantInfo, 8> m_children;
158     OctantInfo m_octant;
159     double m_spacing;
160     double m_squareSpacing;
161 
162     Grid m_grid;
163 };
164 
165 } // namespace bu
166 } // namespace untwine
167