#include #include #include #include "box.h" // --------------------------------------------- Helper function declarations int min(int a, int b); int max(int a, int b); double random_split_ratio(); void box_heap_insert(box_t *heap, int *heap_size, const box_t *box); void box_heap_take_first(box_t *heap, int *heap_size, box_t *first); // ========================================================================== void box_set_volume(box_t *box) { int *extents = box->extents; long volume = 1; int i; for(i = 0; i < N_DIMS; i++) { volume *= extents[i]; } box->volume = volume; } void box_intersect(const box_t *a, const box_t *b, box_t *result) { const int *ac = a->coords, *ae = a->extents; const int *bc = b->coords, *be = b->extents; int i, coordinate, extent; for(i = 0; i < N_DIMS; i++) { coordinate = max(ac[i], bc[i]); extent = min(ac[i] + ae[i], bc[i] + be[i]) - coordinate; result->coords[i] = coordinate; result->extents[i] = extent; } box_set_volume(result); } int box_is_empty(const box_t *b) { const int *extents = b->extents; return extents[X] <= 0 || extents[Y] <= 0 || extents[Z] <= 0; } void box_split(const box_t *original, box_t *a, box_t *b) { const int *extents = original->extents; static int split_dim = 0; int i, j; int max_extent = -1; for(i = 0; i < N_DIMS; i++) { j = (split_dim + i) % N_DIMS; if(max_extent < extents[j]) { max_extent = extents[j]; split_dim = j; } } int ea = (int)round(max_extent * random_split_ratio()); int eb = max_extent - ea; *a = *original; *b = *original; a->extents[split_dim] = ea; b->coords[split_dim] += ea; b->extents[split_dim] = eb; box_set_volume(a); box_set_volume(b); } void box_decompose(const box_t *original, int n_boxes, box_t *boxes) { box_t largest_box, tmp_box, part1, part2; int i, j, n, child1, child2; boxes[0] = *original; n = 1; while(n < n_boxes) { // take out box with maximum volume and split in two box_heap_take_first(boxes, &n, &largest_box); box_split(&largest_box, &part1, &part2); // insert boxes box_heap_insert(boxes, &n, &part1); box_heap_insert(boxes, &n, &part2); } } void box_grow(box_t *box, int extra_width) { int *coords = box->coords; int *extents = box->extents; int i; for(i = 0; i < N_DIMS; i++) { coords[i] -= extra_width; extents[i] += 2 * extra_width; } box_set_volume(box); } // --------------------------------------------------------- Helper functions int min(int a, int b) { return b < a ? b : a; } int max(int a, int b) { return b > a ? b : a; } double random_split_ratio() { const double jitter = 0.085; double ratio = 0.5 - jitter + 2 * jitter * random() / RAND_MAX; return ratio; } void box_heap_insert(box_t *heap, int *heap_size, const box_t *box) { int current = *heap_size; int parent = (current - 1) / 2; box_t tmp = *box; while(current > 0 && heap[parent].volume < tmp.volume) { heap[current] = heap[parent]; current = parent; parent = (current - 1) / 2; } heap[current] = tmp; (*heap_size)++; } void box_heap_take_first(box_t *heap, int *heap_size, box_t *first) { int current = 0; int child = current * 2 + 1; int n = *heap_size - 1; box_t *tail = &heap[n]; *first = heap[current]; *heap_size = n; while(child < n) { if(child+1 < n && heap[child+1].volume > heap[child].volume) child++; if(tail->volume >= heap[child].volume) break; heap[current] = heap[child]; current = child; child = current * 2 + 1; } heap[current] = *tail; } char *box_to_string(const box_t *box, char *buf, int size) { const int *c = box->coords; const int *e = box->extents; snprintf(buf, size, "x: [%5d,%5d); y: [%5d,%5d); z: [%5d,%5d); cells: %ld", c[X], c[X]+e[X], c[Y], c[Y]+e[Y], c[Z], c[Z]+e[Z], box->volume); return buf; }