Antkeeper  0.0.1
rect-pack.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code 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  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef ANTKEEPER_GEOM_RECT_PACK_HPP
21 #define ANTKEEPER_GEOM_RECT_PACK_HPP
22 
24 #include <memory>
25 
26 namespace geom {
27 
33 template <class T>
35 {
37  using scalar_type = T;
38 
41 
43  std::unique_ptr<rect_pack_node> children[2];
44 
46  rect_type bounds{{T{0}, T{0}}, {T{0}, T{0}}};
47 
49  bool occupied{false};
50 };
51 
59 template <class T>
60 class rect_pack
61 {
62 public:
64  using scalar_type = T;
65 
68 
76 
80  rect_pack();
81 
90  void resize(scalar_type w, scalar_type h);
91 
93  void clear();
94 
102  const node_type* pack(scalar_type w, scalar_type h);
103 
105  const node_type& get_root() const;
106 
107 private:
108  static node_type* insert(node_type& parent, scalar_type w, scalar_type h);
109 
110  static void free();
111 
112  node_type root;
113 };
114 
115 template <class T>
117 {
118  root.bounds = {T{0}, T{0}, w, h};
119 }
120 
121 template <class T>
123  rect_pack(0, 0)
124 {}
125 
126 template <class T>
128 {
129  clear();
130  root.bounds = {{T{0}, T{0}}, {w, h}};
131 }
132 
133 template <class T>
135 {
136  root.children[0].reset();
137  root.children[1].reset();
138  root.occupied = false;
139 }
140 
141 template <class T>
143 {
144  return insert(root, w, h);
145 }
146 
147 template <class T>
148 inline const typename rect_pack<T>::node_type& rect_pack<T>::get_root() const
149 {
150  return root;
151 }
152 
153 template <class T>
154 typename rect_pack<T>::node_type* rect_pack<T>::insert(node_type& node, scalar_type w, scalar_type h)
155 {
156  // If not a leaf node
157  if (node.children[0] && node.children[1])
158  {
159  // Attempt to insert into first child
160  node_type* result = insert(*node.children[0], w, h);
161  if (result)
162  {
163  return result;
164  }
165 
166  // Cannot fit in first child, attempt to insert into second child
167  return insert(*node.children[1], w, h);
168 
169  }
170 
171  // Abort if node occupied
172  if (node.occupied)
173  {
174  return nullptr;
175  }
176 
177  // Determine node dimensions
178  scalar_type node_w = node.bounds.max.x() - node.bounds.min.x();
179  scalar_type node_h = node.bounds.max.y() - node.bounds.min.y();
180 
181  // Check if rect is larger than node
182  if (w > node_w || h > node_h)
183  {
184  return nullptr;
185  }
186 
187  // Check for a perfect fit
188  if (w == node_w && h == node_h)
189  {
190  node.occupied = true;
191  return &node;
192  }
193 
194  // Split the node
195  node.children[0] = std::make_unique<node_type>();
196  node.children[1] = std::make_unique<node_type>();
197 
198  // Determine split direction
199  scalar_type dw = node_w - w;
200  scalar_type dh = node_h - h;
201  if (dw > dh)
202  {
203  node.children[0]->bounds.min = node.bounds.min;
204  node.children[0]->bounds.max = {node.bounds.min.x() + w, node.bounds.max.y()};
205  node.children[1]->bounds.min = {node.bounds.min.x() + w, node.bounds.min.y()};
206  node.children[1]->bounds.max = {node.bounds.max};
207  }
208  else
209  {
210  node.children[0]->bounds.min = node.bounds.min;
211  node.children[0]->bounds.max = {node.bounds.max.x(), node.bounds.min.y() + h};
212  node.children[1]->bounds.min = {node.bounds.min.x(), node.bounds.min.y() + h};
213  node.children[1]->bounds.max = {node.bounds.max};
214  }
215 
216  // Insert into first child
217  return insert(*node.children[0], w, h);
218 }
219 
220 } // namespace geom
221 
222 #endif // ANTKEEPER_GEOM_RECT_PACK_HPP
Packs 2D rectangles.
Definition: rect-pack.hpp:61
const node_type * pack(scalar_type w, scalar_type h)
Packs a rect into the rect pack.
Definition: rect-pack.hpp:142
T scalar_type
Scalar type.
Definition: rect-pack.hpp:64
void resize(scalar_type w, scalar_type h)
Clears the pack and resizes the root node bounds.
Definition: rect-pack.hpp:127
rect_pack()
Creates an empty rect pack.
Definition: rect-pack.hpp:122
void clear()
Clear the pack, deallocating all nodes.
Definition: rect-pack.hpp:134
const node_type & get_root() const
Returns a reference to the root node.
Definition: rect-pack.hpp:148
Geometric algorithms.
n-dimensional axis-aligned rectangle.
Node used in 2D rectangle packing.
Definition: rect-pack.hpp:35
bool occupied
true if the node is occupied, false otherwise.
Definition: rect-pack.hpp:49
std::unique_ptr< rect_pack_node > children[2]
Pointers to the two children of the node, if any.
Definition: rect-pack.hpp:43
T scalar_type
Scalar type.
Definition: rect-pack.hpp:37
rect_type bounds
Bounds of the node.
Definition: rect-pack.hpp:46