static __inline__ Uint32 sort_and_split(BBOX_TREE* bbox_tree, Uint32 node, Uint32* index, Uint32 first, Uint32 last) { Uint32 size, i, j, axis[3]; int best_loc; float *area_left, *area_right; float best_index, new_index; #ifdef FASTER_MAP_LOAD AABBOX bbox; #endif size = last - first; if (size < 1) return -1; #ifdef FASTER_MAP_LOAD find_axis_and_bbox(bbox_tree, first, last, axis, &bbox); #else find_axis(bbox_tree, first, last, axis); #endif best_loc = -1; if (size > 8) { area_left = malloc(size * sizeof(float)); area_right = malloc(size * sizeof(float)); for (j = 0; j < 3; j++) { Axis = axis[j]; qsort(bbox_tree->items + first, size, sizeof(BBOX_ITEM), compboxes); build_area_table(bbox_tree, first, last - 1, area_left); build_area_table(bbox_tree, last - 1, first, area_right); best_index = area_right[0] * (size - 3.0); /* * Find the most effective point to split. The best location will be * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2 * are the number of objects in the two groups and A1 and A2 are the * surface areas of the bounding boxes of the two groups. */ for (i = 0; i < size - 1; i++) { new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1]; if (new_index < best_index) { best_index = new_index; best_loc = i + first; } } if (best_loc >= 0) break; } free(area_left); free(area_right); } #ifdef FASTER_MAP_LOAD VAssign(bbox_tree->nodes[node].bbox.bbmin, bbox.bbmin); VAssign(bbox_tree->nodes[node].bbox.bbmax, bbox.bbmax); VAssign(bbox_tree->nodes[node].orig_bbox.bbmin, bbox.bbmin); VAssign(bbox_tree->nodes[node].orig_bbox.bbmax, bbox.bbmax); #else calc_bbox(&bbox_tree->nodes[node].bbox, bbox_tree, first, last); VAssign(bbox_tree->nodes[node].orig_bbox.bbmin, bbox_tree->nodes[node].bbox.bbmin); VAssign(bbox_tree->nodes[node].orig_bbox.bbmax, bbox_tree->nodes[node].bbox.bbmax); #endif bbox_tree->nodes[node].items_index = first; bbox_tree->nodes[node].items_count = size; bbox_tree->nodes[node].dynamic_objects.size = 0; bbox_tree->nodes[node].dynamic_objects.index = 0; bbox_tree->nodes[node].dynamic_objects.items = NULL; if (best_loc < 0) { bbox_tree->nodes[node].nodes[0] = NO_INDEX; bbox_tree->nodes[node].nodes[1] = NO_INDEX; return 1; } else { if (*index+2 >= bbox_tree->nodes_count) { bbox_tree->nodes_count *= 2; bbox_tree->nodes = (BBOX_TREE_NODE*)realloc(bbox_tree->nodes, bbox_tree->nodes_count*sizeof(BBOX_TREE_NODE)); } bbox_tree->nodes[node].nodes[0] = (*index)+0; bbox_tree->nodes[node].nodes[1] = (*index)+1; *index += 2; sort_and_split(bbox_tree, bbox_tree->nodes[node].nodes[0], index, first, best_loc + 1); sort_and_split(bbox_tree, bbox_tree->nodes[node].nodes[1], index, best_loc + 1, last); return 0; } }
static int sort_and_split(BBOX_TREE **Root, BBOX_TREE **&Finite, long *numOfFiniteObjects, long first, long last) { BBOX_TREE *cd; long size, i, best_loc; DBL *area_left, *area_right; DBL best_index, new_index; Axis = find_axis(Finite, first, last); size = last - first; if (size <= 0) { return (1); } Do_Cooperate(1); /* * Actually, we could do this faster in several ways. We could use a * logn algorithm to find the median along the given axis, and then a * linear algorithm to partition along the axis. Oh well. */ QSORT((void *)(&Finite[first]), (unsigned long)size, sizeof(BBOX_TREE *), compboxes); /* * area_left[] and area_right[] hold the surface areas of the bounding * boxes to the left and right of any given point. E.g. area_left[i] holds * the surface area of the bounding box containing Finite 0 through i and * area_right[i] holds the surface area of the box containing Finite * i through size-1. */ area_left = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes"); area_right = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes"); /* Precalculate the areas for speed. */ build_area_table(Finite, first, last - 1, area_left); build_area_table(Finite, last - 1, first, area_right); best_index = area_right[0] * (size - 3.0); best_loc = -1; /* * Find the most effective point to split. The best location will be * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2 * are the number of objects in the two groups and A1 and A2 are the * surface areas of the bounding boxes of the two groups. */ for (i = 0; i < size - 1; i++) { new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1]; if (new_index < best_index) { best_index = new_index; best_loc = i + first; } } POV_FREE(area_left); POV_FREE(area_right); /* * Stop splitting if the BUNCHING_FACTOR is reached or * if splitting stops being effective. */ if ((size <= BUNCHING_FACTOR) || (best_loc < 0)) { cd = create_bbox_node(size); for (i = 0; i < size; i++) { cd->Node[i] = Finite[first+i]; } calc_bbox(&(cd->BBox), Finite, first, last); *Root = (BBOX_TREE *)cd; if (*numOfFiniteObjects > maxfinitecount) { /* Prim array overrun, increase array by 50%. */ maxfinitecount = 1.5 * maxfinitecount; /* For debugging only. */ Debug_Info("Reallocing Finite to %d\n", maxfinitecount); Finite = (BBOX_TREE **)POV_REALLOC(Finite, maxfinitecount * sizeof(BBOX_TREE *), "bounding boxes"); } Finite[*numOfFiniteObjects] = cd; (*numOfFiniteObjects)++; return (1); } else { sort_and_split(Root, Finite, numOfFiniteObjects, first, best_loc + 1); sort_and_split(Root, Finite, numOfFiniteObjects, best_loc + 1, last); return (0); } }
static int sort_and_split(BSPHERE_TREE **Root, BSPHERE_TREE ***Elements, int *nElem, int first, int last, int& maxelements) { int size, i, best_loc; DBL *area_left, *area_right; DBL best_index, new_index; BSPHERE_TREE *cd; int Axis = find_axis(*Elements, first, last); size = last - first; if (size <= 0) { return (1); } /* * Actually, we could do this faster in several ways. We could use a * logn algorithm to find the median along the given axis, and then a * linear algorithm to partition along the axis. Oh well. */ switch(Axis) { case X: QSORT((void *)(*Elements + first), size, sizeof(BSPHERE_TREE *), comp_elements<X>); break; case Y: QSORT((void *)(*Elements + first), size, sizeof(BSPHERE_TREE *), comp_elements<Y>); break; case Z: QSORT((void *)(*Elements + first), size, sizeof(BSPHERE_TREE *), comp_elements<Z>); break; } /* * area_left[] and area_right[] hold the surface areas of the bounding * boxes to the left and right of any given point. E.g. area_left[i] holds * the surface area of the bounding box containing Elements 0 through i and * area_right[i] holds the surface area of the box containing Elements * i through size-1. */ area_left = (DBL *)POV_MALLOC(size * sizeof(DBL), "blob bounding hierarchy"); area_right = (DBL *)POV_MALLOC(size * sizeof(DBL), "blob bounding hierarchy"); /* Precalculate the areas for speed. */ build_area_table(*Elements, first, last - 1, area_left); build_area_table(*Elements, last - 1, first, area_right); best_index = area_right[0] * (size - 3.0); best_loc = - 1; /* * Find the most effective point to split. The best location will be * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2 * are the number of objects in the two groups and A1 and A2 are the * surface areas of the bounding boxes of the two groups. */ for (i = 0; i < size - 1; i++) { new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1]; if (new_index < best_index) { best_index = new_index; best_loc = i + first; } } POV_FREE(area_left); POV_FREE(area_right); /* * Stop splitting if the BRANCHING_FACTOR is reached or * if splitting stops being effective. */ if ((size <= BRANCHING_FACTOR) || (best_loc < 0)) { cd = (BSPHERE_TREE *)POV_MALLOC(sizeof(BSPHERE_TREE), "blob bounding hierarchy"); cd->Entries = (short)size; cd->Node = (BSPHERE_TREE **)POV_MALLOC(size*sizeof(BSPHERE_TREE *), "blob bounding hierarchy"); for (i = 0; i < size; i++) { cd->Node[i] = (*Elements)[first+i]; } recompute_bound(cd); *Root = cd; if (*nElem >= maxelements) { /* Prim array overrun, increase array by 50%. */ maxelements = 1.5 * maxelements; /* For debugging only. */ // TODO FIXME Debug_Info("Reallocing elements to %d\n", maxelements); *Elements = (BSPHERE_TREE **)POV_REALLOC(*Elements, maxelements * sizeof(BSPHERE_TREE *), "bounding slabs"); } (*Elements)[*nElem] = cd; (*nElem)++; return (1); } else { sort_and_split(Root, Elements, nElem, first, best_loc + 1, maxelements); sort_and_split(Root, Elements, nElem, best_loc + 1, last, maxelements); return (0); } }
int sort_and_split(BBOX_TREE **Root, BBOX_TREE **&Finite, size_t *numOfFiniteObjects, ptrdiff_t first, ptrdiff_t last, size_t& maxfinitecount) { BBOX_TREE *cd; ptrdiff_t size, i, best_loc; DBL *area_left, *area_right; DBL best_index, new_index; int Axis = find_axis(Finite, first, last); size = last - first; if(size <= 0) return (1); // Actually, we could do this faster in several ways. We could use a // logn algorithm to find the median along the given axis, and then a // linear algorithm to partition along the axis. Oh well. switch(Axis) { case X: QSORT(reinterpret_cast<void *>(&Finite[first]), size, sizeof(BBOX_TREE *), compboxes<X>); break; case Y: QSORT(reinterpret_cast<void *>(&Finite[first]), size, sizeof(BBOX_TREE *), compboxes<Y>); break; case Z: QSORT(reinterpret_cast<void *>(&Finite[first]), size, sizeof(BBOX_TREE *), compboxes<Z>); break; } // area_left[] and area_right[] hold the surface areas of the bounding // boxes to the left and right of any given point. E.g. area_left[i] holds // the surface area of the bounding box containing Finite 0 through i and // area_right[i] holds the surface area of the box containing Finite // i through size-1. area_left = new DBL[size]; area_right = new DBL[size]; // Precalculate the areas for speed. build_area_table(Finite, first, last - 1, area_left); build_area_table(Finite, last - 1, first, area_right); best_index = area_right[0] * (size - 3.0); best_loc = -1; // Find the most effective point to split. The best location will be // the one that minimizes the function N1*A1 + N2*A2 where N1 and N2 // are the number of objects in the two groups and A1 and A2 are the // surface areas of the bounding boxes of the two groups. for(i = 0; i < size - 1; i++) { new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1]; if(new_index < best_index) { best_index = new_index; best_loc = i + first; } } delete[] area_left; delete[] area_right; // Stop splitting if the BUNCHING_FACTOR is reached or // if splitting stops being effective. if((size <= BUNCHING_FACTOR) || (best_loc < 0)) { cd = create_bbox_node(size); for(i = 0; i < size; i++) cd->Node[i] = Finite[first+i]; calc_bbox(&(cd->BBox), Finite, first, last); *Root = cd; if(*numOfFiniteObjects >= maxfinitecount) { // Prim array overrun, increase array by 50%. maxfinitecount = 1.5 * maxfinitecount; // For debugging only. // TODO MESSAGE Debug_Info("Reallocing Finite to %d\n", maxfinitecount); Finite = reinterpret_cast<BBOX_TREE **>(POV_REALLOC(Finite, maxfinitecount * sizeof(BBOX_TREE *), "bounding boxes")); } Finite[*numOfFiniteObjects] = cd; (*numOfFiniteObjects)++; return (1); } sort_and_split(Root, Finite, numOfFiniteObjects, first, best_loc + 1, maxfinitecount); sort_and_split(Root, Finite, numOfFiniteObjects, best_loc + 1, last, maxfinitecount); return (0); }