2
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
3
// All rights reserved.
5
// This file is part of the Carve CSG Library (http://carve-csg.com/)
7
// This file may be used under the terms of the GNU General Public
8
// License version 2.0 as published by the Free Software Foundation
9
// and appearing in the file LICENSE.GPL2 included in the packaging of
12
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
13
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
14
// A PARTICULAR PURPOSE.
20
#include <carve/carve.hpp>
22
#include <carve/geom.hpp>
23
#include <carve/aabb.hpp>
24
#include <carve/vertex_decl.hpp>
25
#include <carve/edge_decl.hpp>
26
#include <carve/face_decl.hpp>
32
static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Face<3> *face) {
33
if (face->nVertices() == 3) {
34
return aabb.intersects(carve::geom::tri<3>(face->vertex(0)->v, face->vertex(1)->v, face->vertex(2)->v));
36
// partial, conservative SAT.
37
return aabb.intersects(face->aabb) && aabb.intersects(face->plane_eqn);
41
static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Edge<3> *edge) {
42
return aabb.intersectsLineSegment(edge->v1->v, edge->v2->v);
45
static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Vertex<3> *vertex) {
46
return aabb.intersects(vertex->v);
51
struct nodedata_FaceEdge {
52
std::vector<const carve::poly::Face<3> *> faces;
53
std::vector<const carve::poly::Edge<3> *> edges;
55
void add(const carve::poly::Face<3> *face) {
56
faces.push_back(face);
59
void add(const carve::poly::Edge<3> *edge) {
60
edges.push_back(edge);
63
template<typename iter_t>
64
void _fetch(iter_t &iter, const carve::poly::Edge<3> *) {
65
std::copy(edges.begin(), edges.end(), iter);
68
template<typename iter_t>
69
void _fetch(iter_t &iter, const carve::poly::Face<3> *) {
70
std::copy(faces.begin(), faces.end(), iter);
73
template<typename node_t>
74
void propagate(node_t *node) {
77
template<typename iter_t>
78
void fetch(iter_t &iter) {
79
return _fetch(iter, std::iterator_traits<iter_t>::value_type);
85
const static double SLACK_FACTOR = 1.0009765625;
86
const static unsigned MAX_SPLIT_DEPTH = 32;
90
template<unsigned n_dim, typename nodedata_t>
91
class SpatialSubdivTree {
93
typedef carve::geom::aabb<n_dim> aabb_t;
94
typedef carve::geom::vector<n_dim> vector_t;
100
n_children = 1 << n_dim
115
Node(const Node &node); // undefined.
116
Node &operator=(const Node &node); // undefined.
121
inline aabb_t makeAABB() const {
122
vector_t centre = 0.5 * (min + max);
123
vector_t size = SLACK_FACTOR * 0.5 * (max - min);
124
return aabb_t(centre, size);
127
void setup(Node *_parent, const vector_t &_min, const vector_t &_max) {
134
void alloc_children() {
135
vector_t mid = 0.5 * (min + max);
136
children = new Node[n_children];
137
for (size_t i = 0; i < (n_children); ++i) {
138
vector_t new_min, new_max;
139
for (size_t c = 0; c < n_dim; ++c) {
141
new_min.v[c] = min.v[c];
142
new_max.v[c] = mid.v[c];
144
new_min.v[c] = mid.v[c];
145
new_max.v[c] = max.v[c];
148
children[i].setup(this, new_min, new_max);
152
void dealloc_children() {
158
inline bool isLeaf() const { return children == NULL; }
160
Node(Node *_parent, const vector_t &_min, const vector_t &_max) : parent(_parent), children(NULL), min(_min), max(_max) {
171
data.propagate(this);
176
template<typename obj_t>
177
void insert(const obj_t &object) {
179
for (size_t i = 0; i < n_children; ++i) {
180
if (intersection_test(children[i].aabb, object)) {
181
children[i].insert(object);
189
template<typename obj_t>
190
void insertVector(typename std::vector<obj_t>::iterator beg, typename std::vector<obj_t>::iterator end) {
196
for (size_t i = 0; i < n_children; ++i) {
197
typename std::vector<obj_t>::iterator mid = std::partition(beg, end, std::bind1st(intersection_test, children[i].aabb));
198
children[i].insertVector(beg, mid);
203
template<typename iter_t>
204
void insertMany(iter_t begin, iter_t end) {
209
template<typename obj_t, typename iter_t, typename filter_t>
210
void findObjectsNear(const obj_t &object, iter_t &output, filter_t filter) {
212
for (size_t i = 0; i < n_children; ++i) {
213
if (intersection_test(children[i].aabb, object)) {
214
children[i].findObjectsNear(object, output, filter);
222
// bool hasGeometry();
224
// template <class T>
225
// void putInside(const T &input, Node *child, T &output);
233
SpatialSubdivTree(const vector_t &_min, const vector_t &_max) : root(new Node(NULL, _min, _max)) {
236
~SpatialSubdivTree() {
241
template<typename obj_t>
242
bool operator()(const obj_t &obj) const {
248
template<typename obj_t>
249
bool operator()(const obj_t &obj) const {
250
return obj.tag_once();
254
// in order to be used as an input, aabb_t::intersect(const obj_t &) must exist.
255
template<typename obj_t, typename iter_t, typename filter_t>
256
void findObjectsNear(const obj_t &object, iter_t output, filter_t filter) {
257
if (!intersection_test(root->aabb, object)) return;
258
root->findObjectsNear(root, object, output, filter);