Library of Assembled Shared Sources
split_heuristics.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2024 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#ifndef LASS_GUARDIAN_OF_INCLUSION_SPAT_SPLIT_HEURISTICS_H
44#define LASS_GUARDIAN_OF_INCLUSION_SPAT_SPLIT_HEURISTICS_H
45
46#include "spat_common.h"
47
48#include <cstddef>
49
50namespace lass
51{
52namespace spat
53{
54namespace impl
55{
56 template <typename ObjectTraits>
57 typename ObjectTraits::TValue aabbCenterForAxis(const typename ObjectTraits::TAabb& box, size_t axis)
58 {
59 return (ObjectTraits::coord(ObjectTraits::aabbMin(box), axis) + ObjectTraits::coord(ObjectTraits::aabbMax(box), axis)) / 2;
60 };
61
62 template <typename ObjectTraits>
63 class LessAxis
64 {
65 public:
66 LessAxis(size_t iAxis): axis_(iAxis) {}
67 template <typename Input> bool operator()(const Input& a, const Input& b) const
68 {
69 return aabbCenterForAxis<ObjectTraits>(a.aabb, axis_) < aabbCenterForAxis<ObjectTraits>(b.aabb, axis_);
70 }
71 private:
72 size_t axis_;
73 };
74}
75
76
77
78template <typename ObjectTraits>
79struct SplitInfo
80{
81 typedef typename ObjectTraits::TAabb TAabb;
82 typedef typename ObjectTraits::TValue TValue;
83 typedef size_t TAxis;
84
85 constexpr static TAxis dontSplit = size_t(-1);
86
87 SplitInfo(const TAabb& aabb, TValue x, TAxis axis):
88 aabb(aabb), x(x), axis(axis)
89 {
90 }
91
92 static SplitInfo makeLeaf(const TAabb& aabb)
93 {
94 return SplitInfo(aabb, 0, dontSplit);
95 }
96
97 bool isLeaf() const { return axis == dontSplit; }
98
99 TAabb aabb;
100 TValue x;
101 TAxis axis;
102
103private:
104};
105
106
107
108namespace impl
109{
110 template <typename ObjectTraits>
111 class Splitter
112 {
113 public:
114 Splitter(const SplitInfo<ObjectTraits>& split): split_(split) {}
115 template <typename Input> bool operator()(const Input& input) const
116 {
117 return aabbCenterForAxis<ObjectTraits>(input.aabb, split_.axis) <= split_.x;
118 }
119 private:
120 SplitInfo<ObjectTraits> split_;
121 };
122}
123
124
125
126class DefaultSplitHeuristics
127{
128public:
129 DefaultSplitHeuristics(size_t maxObjectsPerLeaf, size_t maxDepth):
130 maxObjectsPerLeaf_(maxObjectsPerLeaf),
131 maxDepth_(maxDepth)
132 {
133 }
134
135 size_t maxObjectsPerLeaf() const { return maxObjectsPerLeaf_; }
136 size_t maxDepth() const { return maxDepth_; }
137
138protected:
139
140 void swap(DefaultSplitHeuristics& other)
141 {
142 std::swap(maxObjectsPerLeaf_, other.maxObjectsPerLeaf_);
143 std::swap(maxDepth_, other.maxDepth_);
144 }
145
146 template <typename ObjectTraits, typename RandomIterator>
147 SplitInfo<ObjectTraits> split(RandomIterator first, RandomIterator last)
148 {
149 typedef typename ObjectTraits::TAabb TAabb;
150 typedef typename ObjectTraits::TPoint TPoint;
151 typedef typename ObjectTraits::TValue TValue;
152
153 LASS_ASSERT(maxObjectsPerLeaf_ > 0);
154
155 TAabb aabb = ObjectTraits::aabbEmpty();
156 for (RandomIterator i = first; i != last; ++i)
157 {
158 aabb = ObjectTraits::aabbJoin(aabb, i->aabb);
159 }
160
161 const size_t n = static_cast<size_t>(last - first);
162 if (n <= maxObjectsPerLeaf_)
163 {
164 return SplitInfo<ObjectTraits>::makeLeaf(aabb);
165 }
166
167 const TPoint min = ObjectTraits::aabbMin(aabb);
168 const TPoint max = ObjectTraits::aabbMax(aabb);
169 size_t axis = 0;
170 TValue maxDistance = ObjectTraits::coord(max, 0) - ObjectTraits::coord(min, 0);
171 for (size_t k = 1; k < ObjectTraits::dimension; ++k)
172 {
173 const TValue distance = ObjectTraits::coord(max, k) - ObjectTraits::coord(min, k);
174 if (distance > maxDistance)
175 {
176 axis = k;
177 maxDistance = distance;
178 }
179 }
180
181 const TValue x = impl::aabbCenterForAxis<ObjectTraits>(aabb, axis);
182 return SplitInfo<ObjectTraits>(aabb, x, axis);
183 }
184
185private:
186 size_t maxObjectsPerLeaf_;
187 size_t maxDepth_;
188};
189
190
191
192class SAHSplitHeuristics
193{
194public:
195 SAHSplitHeuristics(size_t maxObjectsPerLeaf, size_t maxDepth):
196 maxObjectsPerLeaf_(maxObjectsPerLeaf),
197 maxDepth_(maxDepth)
198 {
199 }
200
201 size_t maxObjectsPerLeaf() const { return maxObjectsPerLeaf_; }
202 size_t maxDepth() const { return maxDepth_; }
203
204protected:
205
206 void swap(SAHSplitHeuristics& other)
207 {
208 std::swap(maxObjectsPerLeaf_, other.maxObjectsPerLeaf_);
209 std::swap(maxDepth_, other.maxDepth_);
210 }
211
212 template <typename ObjectTraits, typename RandomIterator>
213 SplitInfo<ObjectTraits> split(RandomIterator first, RandomIterator last)
214 {
215 typedef typename ObjectTraits::TAabb TAabb;
216 typedef typename ObjectTraits::TValue TValue;
217
218 const TValue costNode = 1; // must be non zero!
219 const TValue costObject = 1000;
220
221 LASS_ASSERT(maxObjectsPerLeaf_ > 0);
222
223 const size_t n = static_cast<size_t>(last - first);
224 if (n <= maxObjectsPerLeaf_)
225 {
226 TAabb aabb = ObjectTraits::aabbEmpty();
227 for (RandomIterator i = first; i != last; ++i)
228 {
229 aabb = ObjectTraits::aabbJoin(aabb, i->aabb);
230 }
231 return SplitInfo<ObjectTraits>::makeLeaf(aabb);
232 }
233
234 TValue bestCost = n * costObject;
235 size_t bestAxis = SplitInfo<ObjectTraits>::dontSplit;
236 TValue bestX = 0;
237 std::vector<TValue> leftArea(n);
238 TAabb totalBox = ObjectTraits::aabbEmpty();
239 TValue totalArea = 0;
240
241 for (size_t axis = 0; axis < ObjectTraits::dimension; ++axis)
242 {
243 std::sort(first, last, impl::LessAxis<ObjectTraits>(axis));
244
245 TAabb box = ObjectTraits::aabbEmpty();
246 for (size_t k = 0; k < n; ++k)
247 {
248 RandomIterator i = first + static_cast<std::ptrdiff_t>(k);
249 box = ObjectTraits::aabbJoin(box, i->aabb);
250 leftArea[k] = ObjectTraits::aabbSurfaceArea(box);
251 }
252
253 if (axis == 0)
254 {
255 totalBox = box;
256 totalArea = ObjectTraits::aabbSurfaceArea(totalBox);
257 if (totalArea == 0)
258 {
259 return SplitInfo<ObjectTraits>::makeLeaf(totalBox);
260 }
261 }
262
263 box = ObjectTraits::aabbEmpty();
264 for (size_t k = n; k > 0; --k)
265 {
266 RandomIterator i = first + static_cast<std::ptrdiff_t>(k) - 1;
267 const TValue rightArea = ObjectTraits::aabbSurfaceArea(box);
268 const TValue cost = 2 * costNode + (leftArea[k - 1] * k + rightArea * (n - k)) * costObject / totalArea;
269 if (cost < bestCost)
270 {
271 bestCost = cost;
272 bestAxis = axis;
273 bestX = impl::aabbCenterForAxis<ObjectTraits>(i->aabb, axis);
274 }
275 box = ObjectTraits::aabbJoin(box, i->aabb);
276 }
277 }
278
279 return SplitInfo<ObjectTraits>(totalBox, bestX, bestAxis);
280 }
281
282private:
283
284 size_t maxObjectsPerLeaf_;
285 size_t maxDepth_;
286};
287
288
289
290}
291
292}
293
294#endif
295
296// EOF
std::vector< std::basic_string< Char, Traits, Alloc > > split(const std::basic_string< Char, Traits, Alloc > &to_be_split)
Reflects the Python function split without seperator argument.
Definition basic_ops.h:211
spatial subdivisions, quadtrees, octrees, meshes in 2D and 3D, triangulators, ...
Definition aabb8_tree.h:80
Library for Assembled Shared Sources.
Definition config.h:53