LCOV - code coverage report
Current view: top level - ugbase/common/node_tree - octree.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 103 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2010-2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Sebastian Reiter
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #include <cassert>
      34              : #include <vector>
      35              : #include "octree.h"
      36              : 
      37              : using namespace std;
      38              : 
      39              : namespace ug{
      40              : namespace node_tree
      41              : {
      42              : 
      43              : ////////////////////////////////////////////////////////////////////////
      44              : /**     calculates the bounding box around a set of points*/
      45              : static void
      46            0 : CalculateBoundingBox(vector3& boxMinOut, vector3& boxMaxOut,
      47              :                                         const vector3* points, size_t numPoints)
      48              : {
      49            0 :         if(numPoints < 1){
      50              :                 boxMinOut = boxMaxOut = vector3(0, 0, 0);
      51            0 :                 return;
      52              :         }
      53              :         
      54              :         boxMinOut = boxMaxOut = points[0];
      55              :         
      56            0 :         for(size_t i = 0; i < numPoints; ++i){
      57            0 :                 for(size_t j = 0; j < 3; ++j)
      58              :                 {
      59            0 :                         const number& coord = points[i][j];
      60            0 :                         if(coord < boxMinOut[j])
      61            0 :                                 boxMinOut[j]  = coord;
      62            0 :                         else if(coord > boxMaxOut[j])
      63            0 :                                 boxMaxOut[j]  = coord;
      64              :                 }
      65              :         }
      66              : }
      67              : 
      68              : ////////////////////////////////////////////////////////////////////////
      69              : /**     calculates the bounding box around a set of elements which are
      70              :  *      given by a set of indices referencing a set of points. This method
      71              :  *      is particularily useful if the elements only reference a subset
      72              :  *      of the given points. If not the bounding box should be calculated
      73              :  *      directly on the set of points.
      74              :  */
      75              : static void
      76            0 : CalculateBoundingBox(vector3& boxMinOut, vector3& boxMaxOut,
      77              :                                         const vector3* points,
      78              :                                         const int* inds, size_t numInds)
      79              : {
      80            0 :         if(numInds < 1){
      81              :                 boxMinOut = boxMaxOut = vector3(0, 0, 0);
      82            0 :                 return;
      83              :         }
      84              :         
      85            0 :         boxMinOut = boxMaxOut = points[inds[0]];
      86              :         
      87            0 :         for(size_t i = 0; i < numInds; ++i){
      88            0 :                 for(size_t j = 0; j < 3; ++j)
      89              :                 {
      90            0 :                         const number& coord = points[inds[i]][j];
      91            0 :                         if(coord < boxMinOut[j])
      92            0 :                                 boxMinOut[j]  = coord;
      93            0 :                         else if(coord > boxMaxOut[j])
      94            0 :                                 boxMaxOut[j]  = coord;
      95              :                 }
      96              :         }
      97              : }
      98              : 
      99              : ////////////////////////////////////////////////////////////////////////
     100              : /**     Increases the size of the bounding box by scaling around its center*/
     101            0 : static void GrowBox(vector3& minInOut, vector3& maxInOut, number scaleFac)
     102              : {
     103              :         vector3 halfDiag;
     104              :         VecSubtract(halfDiag, maxInOut, minInOut);
     105              :         VecScale(halfDiag, halfDiag, 0.5);
     106              :         VecScale(halfDiag, halfDiag, scaleFac);
     107              :         
     108              :         vector3 center;
     109              :         VecAdd(center, minInOut, maxInOut);
     110              :         VecScale(center, center, 0.5);
     111              :         
     112              :         VecAdd(maxInOut, center, halfDiag);
     113              :         VecSubtract(minInOut, center, halfDiag);
     114            0 : }
     115              : 
     116              : ////////////////////////////////////////////////////////////////////////
     117              : //      CreateOctree
     118              : SPCollisionTreeRootNode 
     119            0 : CreateOctree(vector3* points, size_t numPoints,
     120              :                           int* elemInds, size_t numElemInds, int numIndsPerElem,
     121              :                           CollisionElementID* elemIDs, int maxDepth,
     122              :                           int elemThreshold, bool bLoose)
     123              : {
     124              : //      if there are no elements, we'll return an empty node
     125            0 :         if(numElemInds == 0)
     126              :                 return SPCollisionTreeRootNode(NULL);
     127              :                 
     128              : //      if the number of indices per elements is not right, we'll return, too.
     129            0 :         if(numIndsPerElem < 2 || numIndsPerElem > 3)
     130              :                 return SPCollisionTreeRootNode(NULL);
     131              : 
     132              : //      calculate the bounding-box of the tree
     133              :         vector3 boxMin, boxMax;
     134            0 :         CalculateBoundingBox(boxMin, boxMax, points, numPoints);
     135            0 :         GrowBox(boxMin, boxMax, 1.001);
     136              :         
     137              : //      create the root-node
     138            0 :         SPCollisionTreeRootNode spRootNode = CollisionTreeRootNode::create();
     139              :         
     140              : //      add the given points to the root-node
     141            0 :         spRootNode->add_points(points, numPoints);
     142              :         
     143              : //      set the bounding-box of the root-node
     144            0 :         spRootNode->set_box(boxMin, boxMax);
     145              :         
     146              : //      create the sub-trees
     147            0 :         CreateSubOctrees(spRootNode.get(), points, numPoints, elemInds,
     148              :                                         numElemInds, numIndsPerElem, elemIDs, maxDepth,
     149              :                                         elemThreshold, bLoose);
     150              : 
     151              : //      done. return the root-node
     152              :         return spRootNode;
     153              : }
     154              : 
     155              : ////////////////////////////////////////////////////////////////////////
     156              : //      CreateSubOctrees
     157            0 : void CreateSubOctrees(BoxedGroupNode* parentNode,
     158              :                                           vector3* points, size_t numPoints,
     159              :                                           int* elemInds, size_t numElemInds, int numIndsPerElem,
     160              :                                           CollisionElementID* elemIDs, int maxDepth,
     161              :                                           int elemThreshold, bool bLoose)
     162              : {
     163              : //      the maximal number of indices per element.
     164              : //      has to be adjusted if new element-types are supported.
     165              :         assert(numIndsPerElem > 1 && numIndsPerElem <= 3 &&
     166              :                         "unsupported number of indices per element.");
     167              : 
     168              : //      the number of elements
     169            0 :         int numElems = numElemInds / numIndsPerElem;
     170              :         
     171              : //      check if subnodes have to be created
     172            0 :         if((maxDepth > 0) && (numElems > elemThreshold))
     173              :         {
     174              :         //      yes, we have to create subnodes.
     175              :                 vector3 boxMin, boxMax;
     176            0 :                 boxMin = parentNode->min_corner();
     177            0 :                 boxMax = parentNode->max_corner();
     178              :                 
     179              :                 vector3 boxSize;
     180            0 :                 boxSize.x() = boxMax.x() - boxMin.x();
     181            0 :                 boxSize.y() = boxMax.y() - boxMin.y();
     182            0 :                 boxSize.z() = boxMax.z() - boxMin.z();
     183              :                 
     184              :         //      we'll store index-lists of subtrees in those vectors
     185              :                 vector<int>                               vNewElems;
     186              :                 vector<CollisionElementID>        vNewIDs;
     187              : //TODO: check whether vNewElems.reserve amd vNewIDs.reserve would result in a speedup.
     188              : 
     189              :         //      if a loose tree shall be generated, we'll have to record
     190              :         //      whether an edge has already been assigned or not.
     191              :                 vector<char> elemAssigned;
     192            0 :                 if(bLoose)
     193            0 :                         elemAssigned.resize(numElems, 0);
     194              : 
     195              :         //      iterate through each sub-tree
     196            0 :                 for(size_t subNodeInd = 0; subNodeInd < 8; ++subNodeInd)
     197              :                 {
     198              :                 //      clear arrays
     199              :                         vNewElems.clear();
     200              :                         vNewIDs.clear();
     201              : 
     202              :                 //      create the box of the subnode
     203              :                         vector3 subBoxMin, subBoxMax;
     204              : 
     205              :                 //      compute bounding box from ParentBox and index
     206            0 :                         subBoxMin.x() = boxMin.x() + .5 * boxSize.x() * (subNodeInd % 2);
     207            0 :                         subBoxMin.y() = boxMin.y() + .5 * boxSize.y() * (int)(subNodeInd / 4);
     208            0 :                         subBoxMin.z() = boxMin.z() + .5 * boxSize.z() * (int)((subNodeInd % 4) / 2);
     209            0 :                         subBoxMax.x() = subBoxMin.x() + .5 * boxSize.x();
     210            0 :                         subBoxMax.y() = subBoxMin.y() + .5 * boxSize.y();
     211            0 :                         subBoxMax.z() = subBoxMin.z() + .5 * boxSize.z();
     212              :                         
     213              :                 //      find the elements that are inside the box.
     214              :                 //      different approaches have to be taken, depending on
     215              :                 //      whether a loose tree shall be created or not.
     216            0 :                         if(bLoose){
     217            0 :                                 GrowBox(subBoxMin, subBoxMax, 1.001);
     218              :                         //      create a loose tree.
     219              :                         //      check for each element whether the center lies in the box or not.
     220            0 :                                 for(size_t i = 0; i < numElemInds; i += numIndsPerElem)
     221              :                                 {
     222            0 :                                         size_t elemIndex = i / numIndsPerElem;
     223              :                                         
     224            0 :                                         if(!elemAssigned[elemIndex])
     225              :                                         {
     226              :                                         //      calculate the center
     227              :                                                 vector3 center(0, 0, 0);
     228            0 :                                                 for(int j = 0; j < numIndsPerElem; ++j){
     229            0 :                                                         VecAdd(center, center, points[elemInds[i + j]]);
     230              :                                                 }
     231              :                                                 
     232            0 :                                                 VecScale(center, center, 1. / numIndsPerElem);
     233              :                                         
     234              :                                         //      check whether the center lies in the bounding box
     235            0 :                                                 if(BoxBoundProbe(center, subBoxMin, subBoxMax))
     236              :                                                 {
     237              :                                                 //      it does. Mark the element as assigned and
     238              :                                                 //      add it to the new-lists.
     239            0 :                                                         elemAssigned[elemIndex] = 1;
     240              :                                                         
     241            0 :                                                         for(int j = 0; j < numIndsPerElem; ++j)
     242            0 :                                                                 vNewElems.push_back(elemInds[i + j]);
     243              :                                                                 
     244            0 :                                                         if(elemIDs)
     245            0 :                                                                 vNewIDs.push_back(elemIDs[elemIndex]);
     246              :                                                 }
     247              :                                         }
     248              :                                 }
     249              :                                 
     250              :                         //      all elements for this sub-tree have been collected.
     251              :                         //      Since it is a loose tree, we'll have to readjust the box
     252            0 :                                 CalculateBoundingBox(subBoxMin, subBoxMax, points,
     253              :                                                                         &vNewElems.front(), vNewElems.size());
     254              :                                                                         
     255            0 :                                 GrowBox(subBoxMin, subBoxMax, 1.001);
     256              :                         }
     257              :                         else{
     258              : //TODO: check whether moving the element-iteration into the switch would
     259              : //              result in a noticeable speedup (I don't think so!).
     260              : 
     261              :                         //      the tree is not loose. We have to find all elements that
     262              :                         //      intersect the box.
     263            0 :                                 for(size_t i = 0; i < numElemInds; i += numIndsPerElem)
     264              :                                 {
     265              :                                 //      check whether elements are lines or triangles
     266              :                                         bool intersects = false;
     267            0 :                                         switch(numIndsPerElem)
     268              :                                         {
     269            0 :                                         case 2: // elements are line-segments
     270            0 :                                                 intersects = LineBoxIntersection(points[elemInds[i]],
     271            0 :                                                                                                                 points[elemInds[i + 1]],
     272              :                                                                                                                 subBoxMin, subBoxMax);
     273            0 :                                                 break;
     274              :                                                 
     275            0 :                                         case 3: // elements are triangles
     276            0 :                                                 intersects = TriangleBoxIntersection(
     277            0 :                                                                                 points[elemInds[i]], points[elemInds[i + 1]],
     278            0 :                                                                                 points[elemInds[i + 2]], subBoxMin, subBoxMax);
     279              :                                                 break;
     280              :                                         default:
     281              :                                                 intersects = false;
     282              :                                                 break;
     283              :                                         }
     284              :                                         
     285              :                                 //      if we found an intersection, the element has to be assigned
     286              :                                 //      to the subtree, which is associated with the box.
     287            0 :                                         if(intersects){
     288            0 :                                                 for(int j = 0; j < numIndsPerElem; ++j)
     289            0 :                                                         vNewElems.push_back(elemInds[i + j]);
     290              :                                                 
     291            0 :                                                 if(elemIDs)
     292            0 :                                                         vNewIDs.push_back(elemIDs[i / numIndsPerElem]);
     293              :                                         }
     294              :                                 }
     295              :                         }
     296              : 
     297              :                 //      all elements that go into this subtree have been found.
     298              :                 //      now create the subtree
     299            0 :                         SPBoxedGroupNode spSubNode = BoxedGroupNode::create();
     300            0 :                         spSubNode->set_box(subBoxMin, subBoxMax);
     301            0 :                         parentNode->add_child(spSubNode);
     302              : 
     303            0 :                         if(elemIDs)
     304            0 :                                 CreateSubOctrees(spSubNode.get(), points, numPoints,
     305              :                                                                 &vNewElems.front(), vNewElems.size(), numIndsPerElem,
     306              :                                                                 &vNewIDs.front(), maxDepth - 1, elemThreshold, bLoose);
     307              :                         else
     308            0 :                                 CreateSubOctrees(spSubNode.get(), points, numPoints,
     309              :                                                                 &vNewElems.front(), vNewElems.size(), numIndsPerElem,
     310              :                                                                 NULL, maxDepth - 1, elemThreshold, bLoose);
     311              :                 }
     312            0 :         }
     313              :         else{
     314              :         //      there are less elements thatn elemThreshold or maxDepth is reached.
     315              :         //      We will now create the tree-node that holds the elements.
     316              :         //      If there are no elements, we can return immediatly.
     317            0 :                 if(numElemInds == 0)
     318              :                         return;
     319              :                         
     320              :         //      We have to distinguish between the different element-types
     321            0 :                 switch(numIndsPerElem){
     322            0 :                 case 2://       edges
     323              :                         {
     324            0 :                                 SPCollisionEdgesNode spNode = CollisionEdgesNode::create();
     325            0 :                                 if(elemIDs)
     326            0 :                                         spNode->add_edges(elemInds, elemIDs, numElemInds / 2);
     327              :                                 else
     328            0 :                                         spNode->add_edges(elemInds, numElemInds / 2);
     329              :                                         
     330            0 :                                 parentNode->add_child(spNode);
     331              :                         }
     332            0 :                         break;
     333              :                         
     334            0 :                 case 3://       triangles
     335              :                         {
     336            0 :                                 SPCollisionTrianglesNode spNode = CollisionTrianglesNode::create();
     337            0 :                                 if(elemIDs)
     338            0 :                                         spNode->add_triangles(elemInds, elemIDs, numElemInds / 3);
     339              :                                 else
     340            0 :                                         spNode->add_triangles(elemInds, numElemInds / 3);
     341              : 
     342            0 :                                 parentNode->add_child(spNode);
     343              :                         }
     344            0 :                         break;
     345              :                         
     346              :                 default:
     347              :                         break;
     348              :                 }
     349              :         }
     350              : }
     351              : 
     352              : 
     353              : }//     end of namesapce node_tree
     354              : }//     end of namespace ug
     355              : 
        

Generated by: LCOV version 2.0-1