// Create a bounding box hierarchy from a given list of finite and // infinite elements. Each element consists of // // - an infinite flag // - a bounding box enclosing the element // - a pointer to the structure representing the element (e.g an object) void Build_BBox_Tree(BBOX_TREE **Root, size_t numOfFiniteObjects, BBOX_TREE **&Finite, size_t numOfInfiniteObjects, BBOX_TREE **Infinite, size_t& maxfinitecount) { ptrdiff_t low, high; BBOX_TREE *cd, *root; // This is a resonable guess at the number of finites needed. // This array will be reallocated as needed if it isn't. maxfinitecount = 2 * numOfFiniteObjects; // Now do a sort on the objects, with the end result being // a tree of objects sorted along the x, y, and z axes. if(numOfFiniteObjects > 0) { low = 0; high = numOfFiniteObjects; while(sort_and_split(Root, Finite, &numOfFiniteObjects, low, high, maxfinitecount) == 0) { low = high; high = numOfFiniteObjects; } // Move infinite objects in the first leaf of Root. if(numOfInfiniteObjects > 0) { root = *Root; root->Node = reinterpret_cast<BBOX_TREE **>(POV_REALLOC(root->Node, (root->Entries + 1) * sizeof(BBOX_TREE *), "composite")); POV_MEMMOVE(&(root->Node[1]), &(root->Node[0]), root->Entries * sizeof(BBOX_TREE *)); root->Entries++; cd = create_bbox_node(numOfInfiniteObjects); for(size_t i = 0; i < numOfInfiniteObjects; i++) cd->Node[i] = Infinite[i]; calc_bbox(&(cd->BBox), Infinite, 0, numOfInfiniteObjects); root->Node[0] = cd; calc_bbox(&(root->BBox), root->Node, 0, root->Entries); // Root and first node are infinite. root->Infinite = true; root->Node[0]->Infinite = true; } } else { // There are no finite objects and no Root was created. // Create it now and put all infinite objects into it. if(numOfInfiniteObjects > 0) { cd = create_bbox_node(numOfInfiniteObjects); for(size_t i = 0; i < numOfInfiniteObjects; i++) cd->Node[i] = Infinite[i]; calc_bbox(&(cd->BBox), Infinite, 0, numOfInfiniteObjects); *Root = cd; (*Root)->Infinite = true; } } }
void Build_Bounding_Slabs(BBOX_TREE **Root) { long i, iFinite, iInfinite; BBOX_TREE **Finite, **Infinite; OBJECT *Object, *Temp; /* Count frame level and infinite objects. */ Object = Frame.Objects; numberOfFiniteObjects = numberOfInfiniteObjects = numberOfLightSources = 0; while (Object != NULL) { if (Object->Type & LIGHT_SOURCE_OBJECT) { Temp = ((LIGHT_SOURCE *)Object)->Children; numberOfLightSources++; } else { Temp = Object; } if (Temp != NULL) { if (Test_Flag(Temp, INFINITE_FLAG)) { numberOfInfiniteObjects++; } else { numberOfFiniteObjects++; } } Object = Object->Sibling; } /* If bounding boxes aren't used we can return. */ if (!opts.Use_Slabs || !(numberOfFiniteObjects + numberOfInfiniteObjects >= opts.BBox_Threshold) || (numberOfFiniteObjects + numberOfInfiniteObjects < 1)) { opts.Use_Slabs = false; return; } opts.Use_Slabs = true; /* * This is a resonable guess at the number of finites needed. * This array will be reallocated as needed if it isn't. */ maxfinitecount = 2 * numberOfFiniteObjects; /* * Now allocate an array to hold references to these finites and * any new composite objects we may generate. */ Finite = Infinite = NULL; if (numberOfFiniteObjects > 0) { Finite = (BBOX_TREE **)POV_MALLOC(maxfinitecount*sizeof(BBOX_TREE *), "bounding boxes"); } /* Create array to hold pointers to infinite objects. */ if (numberOfInfiniteObjects > 0) { Infinite = (BBOX_TREE **)POV_MALLOC(numberOfInfiniteObjects*sizeof(BBOX_TREE *), "bounding boxes"); } /* Init lists. */ for (i = 0; i < numberOfFiniteObjects; i++) { Finite[i] = create_bbox_node(0); } for (i = 0; i < numberOfInfiniteObjects; i++) { Infinite[i] = create_bbox_node(0); } /* Set up finite and infinite object lists. */ iFinite = iInfinite = 0; for (Object = Frame.Objects; Object != NULL; Object = Object->Sibling) { if (Object->Type & LIGHT_SOURCE_OBJECT) { Temp = ((LIGHT_SOURCE *)Object)->Children; } else { Temp = Object; } if (Temp != NULL) { /* Add object to the appropriate list. */ if (Test_Flag(Temp, INFINITE_FLAG)) { Infinite[iInfinite]->Infinite = true; Infinite[iInfinite]->BBox = Temp->BBox; Infinite[iInfinite]->Node = (BBOX_TREE **)Temp; iInfinite++; } else { Finite[iFinite]->BBox = Temp->BBox; Finite[iFinite]->Node = (BBOX_TREE **)Temp; iFinite++; } } } /* * Now build the bounding box tree. */ Build_BBox_Tree(Root, numberOfFiniteObjects, Finite, numberOfInfiniteObjects, Infinite); /* Get rid of the Finite and Infinite arrays and just use Root. */ if (Finite != NULL) { POV_FREE(Finite); } if (Infinite != NULL) { POV_FREE(Infinite); } }
void Build_BBox_Tree(BBOX_TREE **Root, long numOfFiniteObjects, BBOX_TREE **&Finite, long numOfInfiniteObjects, BBOX_TREE **Infinite) { short i; long low, high; BBOX_TREE *cd, *root; /* * This is a resonable guess at the number of finites needed. * This array will be reallocated as needed if it isn't. */ maxfinitecount = 2 * numOfFiniteObjects; /* * Now do a sort on the objects, with the end result being * a tree of objects sorted along the x, y, and z axes. */ if (numOfFiniteObjects > 0) { low = 0; high = numOfFiniteObjects; while (sort_and_split(Root, Finite, &numOfFiniteObjects, low, high) == 0) { low = high; high = numOfFiniteObjects; Do_Cooperate(0); } /* Move infinite objects in the first leaf of Root. */ if (numOfInfiniteObjects > 0) { root = (BBOX_TREE *)(*Root); root->Node = (BBOX_TREE **)POV_REALLOC(root->Node, (root->Entries + 1) * sizeof(BBOX_TREE *), "composite"); POV_MEMMOVE(&(root->Node[1]), &(root->Node[0]), root->Entries * sizeof(BBOX_TREE *)); root->Entries++; cd = create_bbox_node(numOfInfiniteObjects); for (i = 0; i < numOfInfiniteObjects; i++) { cd->Node[i] = Infinite[i]; } calc_bbox(&(cd->BBox), Infinite, 0, numOfInfiniteObjects); root->Node[0] = (BBOX_TREE *)cd; calc_bbox(&(root->BBox), root->Node, 0, root->Entries); /* Root and first node are infinite. */ root->Infinite = true; root->Node[0]->Infinite = true; } } else { /* * There are no finite objects and no Root was created. * Create it now and put all infinite objects into it. */ if (numOfInfiniteObjects > 0) { cd = create_bbox_node(numOfInfiniteObjects); for (i = 0; i < numOfInfiniteObjects; i++) { cd->Node[i] = Infinite[i]; } calc_bbox(&(cd->BBox), Infinite, 0, numOfInfiniteObjects); *Root = (BBOX_TREE *)cd; (*Root)->Infinite = true; } } }
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); } }
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); }
void Build_Bounding_Slabs(BBOX_TREE **Root, vector<ObjectPtr>& objects, unsigned int& numberOfFiniteObjects, unsigned int& numberOfInfiniteObjects, unsigned int& numberOfLightSources) { ptrdiff_t iFinite, iInfinite; BBOX_TREE **Finite, **Infinite; ObjectPtr Temp; size_t maxfinitecount = 0; // Count frame level and infinite objects. numberOfFiniteObjects = numberOfInfiniteObjects = numberOfLightSources = 0; for(vector<ObjectPtr>::iterator i(objects.begin()); i != objects.end(); i++) { if((*i)->Type & LIGHT_SOURCE_OBJECT) { if((reinterpret_cast<LightSource *>(*i))->children.size() > 0) { Temp = (reinterpret_cast<LightSource *>(*i))->children[0]; numberOfLightSources++; } else Temp = NULL; } else Temp = (*i); if(Temp != NULL) { if(Test_Flag(Temp, INFINITE_FLAG)) numberOfInfiniteObjects++; else numberOfFiniteObjects++; } } // If bounding boxes aren't used we can return. if(numberOfFiniteObjects + numberOfInfiniteObjects < 1) return; // This is a resonable guess at the number of finites needed. // This array will be reallocated as needed if it isn't. maxfinitecount = 2 * numberOfFiniteObjects; // Now allocate an array to hold references to these finites and // any new composite objects we may generate. Finite = Infinite = NULL; if(numberOfFiniteObjects > 0) Finite = new BBOX_TREE* [maxfinitecount]; // Create array to hold pointers to infinite objects. if(numberOfInfiniteObjects > 0) Infinite = new BBOX_TREE* [numberOfInfiniteObjects]; // Init lists. for(int i = 0; i < numberOfFiniteObjects; i++) Finite[i] = create_bbox_node(0); for(int i = 0; i < numberOfInfiniteObjects; i++) Infinite[i] = create_bbox_node(0); // Set up finite and infinite object lists. iFinite = iInfinite = 0; for(vector<ObjectPtr>::iterator i(objects.begin()); i != objects.end(); i++) { if((*i)->Type & LIGHT_SOURCE_OBJECT) { if((reinterpret_cast<LightSource *>(*i))->children.size() > 0) Temp = (reinterpret_cast<LightSource *>(*i))->children[0]; else Temp = NULL; } else Temp = (*i); if(Temp != NULL) { // Add object to the appropriate list. if(Test_Flag(Temp, INFINITE_FLAG)) { Infinite[iInfinite]->Infinite = true; Infinite[iInfinite]->BBox = Temp->BBox; Infinite[iInfinite]->Node = reinterpret_cast<BBOX_TREE **>(Temp); iInfinite++; } else { Finite[iFinite]->BBox = Temp->BBox; Finite[iFinite]->Node = reinterpret_cast<BBOX_TREE **>(Temp); iFinite++; } } } // Now build the bounding box tree. Build_BBox_Tree(Root, numberOfFiniteObjects, Finite, numberOfInfiniteObjects, Infinite, maxfinitecount); // Get rid of the Finite and Infinite arrays and just use Root. if(Finite != NULL) delete[] Finite; if(Infinite != NULL) delete[] Infinite; }