Advertisement
AlexandraTs

Volumetric B-tree

May 4th, 2023
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.85 KB | None | 0 0
  1. #include <iostream>
  2. #include <fstream>
  3. #include<algorithm>
  4. #include <vector>
  5. #include <memory>
  6. #include <bitset>
  7. #include <map>
  8.  
  9. struct Point {
  10.     float x;
  11.     float y;
  12.     float z;
  13.  
  14.     bool operator>=(const Point& other) const
  15.     {
  16.         return x >= other.x && y >= other.y && z >= other.z;
  17.     }
  18. };
  19.  
  20. struct BoundingBox {
  21.     BoundingBox(bool isZero = true, const Point& low = { INFINITY ,INFINITY ,INFINITY }, const Point& high = { -INFINITY ,-INFINITY ,-INFINITY })
  22.         : m_isZero(isZero)
  23.         , m_Low(low)
  24.         , m_High(high)
  25.     {}
  26.  
  27.     BoundingBox& operator+=(const BoundingBox& other)
  28.     {
  29.         m_Low.x = std::min(m_Low.x, other.m_Low.x);
  30.         m_Low.y = std::min(m_Low.y, other.m_Low.y);
  31.         m_Low.z = std::min(m_Low.z, other.m_Low.z);
  32.  
  33.         m_High.x = std::max(m_High.x, other.m_High.x);
  34.         m_High.y = std::max(m_High.y, other.m_High.y);
  35.         m_High.z = std::max(m_High.z, other.m_High.z);
  36.  
  37.         m_isZero = m_isZero && other.m_isZero;
  38.  
  39.         return *this;
  40.     }
  41.  
  42.     BoundingBox& operator^=(const BoundingBox& other)
  43.     {
  44.         if (m_High >= other.m_Low && other.m_High >= m_Low)
  45.         {
  46.             m_Low.x = std::max(m_Low.x, other.m_Low.x);
  47.             m_Low.y = std::max(m_Low.y, other.m_Low.y);
  48.             m_Low.z = std::max(m_Low.z, other.m_Low.z);
  49.  
  50.             m_High.x = std::min(m_High.x, other.m_High.x);
  51.             m_High.y = std::min(m_High.y, other.m_High.y);
  52.             m_High.z = std::min(m_High.z, other.m_High.z);
  53.  
  54.             m_isZero = m_isZero || other.m_isZero;
  55.         }
  56.         else
  57.         {
  58.             m_isZero = true;
  59.             m_Low = { INFINITY ,INFINITY ,INFINITY };
  60.             m_High = { -INFINITY ,-INFINITY ,-INFINITY };
  61.         }
  62.         return *this;
  63.     }
  64.  
  65.     float size() const
  66.     {
  67.         return m_isZero? 0 : (m_High.x - m_Low.x) * (m_High.y - m_Low.y) * (m_High.z - m_Low.z);
  68.     }
  69.    
  70.     bool m_isZero;
  71.     Point m_Low;
  72.     Point m_High;
  73. };
  74.  
  75. enum class BoundedObjectType {
  76.     BoundingBox = 0,
  77.     BBTree,
  78.     Polygon
  79. };
  80.  
  81. class BoundedObject {
  82. public:
  83.     BoundedObject(BoundedObjectType type = BoundedObjectType::BoundingBox)
  84.                 : m_type(type)
  85.     {}
  86.  
  87.     virtual ~BoundedObject() {}
  88.    
  89.     virtual const BoundingBox& GetBound() = 0;
  90.  
  91.     BoundedObjectType GetType()
  92.     {
  93.         return m_type;
  94.     }
  95.  
  96. private:
  97.     BoundedObjectType m_type;
  98. };
  99.  
  100. class Polygon : public BoundedObject
  101. {
  102. public:
  103.     Polygon(std::vector<Point>& inputPoints)
  104.         :BoundedObject(BoundedObjectType::Polygon)
  105.     {
  106.         points = inputPoints;
  107.         for (auto& point : points)
  108.         {
  109.             box += BoundingBox(false, point, point);
  110.         }
  111.     }
  112.     virtual ~Polygon() {}
  113.  
  114.     virtual const BoundingBox& GetBound() { return box; };
  115. private:
  116.     BoundingBox box;
  117.     std::vector<Point> points;
  118. };
  119.  
  120. template <typename T=BoundedObject, int k=10>
  121. class BBTree : public BoundedObject
  122. {
  123. public:
  124.     BBTree()
  125.         :m_IsLeafLevel(true)
  126.         , m_Parent(nullptr)
  127.     {
  128.         m_Objects.reserve(k);
  129.     }
  130.     virtual ~BBTree() {}
  131.  
  132.     virtual const BoundingBox& GetBound() { return m_TotalBounds; };
  133.    
  134.     void add(std::shared_ptr<BoundedObject> object)
  135.     {
  136.         auto& objBound = object->GetBound();
  137.         m_TotalBounds += objBound;
  138.  
  139.         //if it's a leaf, insert straight away
  140.         if (m_IsLeafLevel)
  141.         {
  142.             m_Objects.push_back(object);
  143.         }
  144.         else
  145.         {
  146.             int foundIdx = 0;
  147.             float minAdditionalVolume = INFINITY;
  148.             for (int idx = 0 ; idx<m_Objects.size() ; ++idx)
  149.             {
  150.                 BoundingBox cpyBound = m_Objects[idx]->GetBound();
  151.                 float cpyVolume = cpyBound.size();
  152.                 cpyBound += objBound;
  153.                 cpyVolume = cpyBound.size() - cpyVolume;
  154.                 if (cpyVolume < minAdditionalVolume)
  155.                 {
  156.                     foundIdx = idx;
  157.                     minAdditionalVolume = cpyVolume;
  158.                 }
  159.             }
  160.             ((BBTree<T, k>*) m_Objects[foundIdx].get())->add(object);
  161.         }
  162.         //if it's not a leaf, find which child node will accept the current object with minimal additional volume and insert it there
  163.  
  164.         // if the size isn't k, there's no need to split the current object
  165.         if (m_Objects.size() < k)
  166.         {
  167.             return;
  168.         }
  169.        
  170.         // find the best split of the objects in the current tree node (this alogirhm may not be that good as it's O(k^3)
  171.         float minimalIntersection = INFINITY;
  172.         std::bitset<k> minimalSplit;
  173.  
  174.         for (int i = 0; i < k; ++i)
  175.         {
  176.             BoundingBox currentBox = m_Objects[i]->GetBound();
  177.             std::bitset<k> takenElems;
  178.             takenElems[i] = true;
  179.             for (int filledElements = 1; filledElements < k / 2; ++filledElements)
  180.             {
  181.                 int minElem = -1;
  182.                 BoundingBox minElemBox;
  183.                 for (int j = 0; j < k; ++j)
  184.                 {
  185.                     if (takenElems[j]) continue;
  186.                     if (minElem == -1)
  187.                     {
  188.                         minElem = j;
  189.                         minElemBox = m_Objects[j]->GetBound();
  190.                         minElemBox += currentBox;
  191.                     }
  192.                     else
  193.                     {
  194.                         BoundingBox testBox = m_Objects[j]->GetBound();
  195.                         testBox += currentBox;
  196.                         if (testBox.size() < minElemBox.size())
  197.                         {
  198.                             minElem = j;
  199.                             minElemBox = testBox;
  200.                         }
  201.                     }
  202.                 }
  203.                 //if (minElem == -1) continue; should never happen
  204.                 takenElems[minElem] = true;
  205.                 currentBox = minElemBox;
  206.             }
  207.             BoundingBox otherBox;
  208.             for (int j = 0; j < k; ++j)
  209.             {
  210.                 if (takenElems[j]) continue;
  211.                 otherBox += m_Objects[j]->GetBound();
  212.             }
  213.             currentBox ^= otherBox;
  214.             if (currentBox.size() < minimalIntersection)
  215.             {
  216.                 minimalIntersection = currentBox.size();
  217.                 minimalSplit = takenElems;
  218.             }
  219.         }
  220.  
  221.         std::vector<std::shared_ptr<BoundedObject>> ltObjects; ltObjects.reserve(k);
  222.         std::shared_ptr<BoundedObject> rtObject(new BBTree<T, k>());
  223.         std::vector<std::shared_ptr<BoundedObject>>& rtObjects = ((BBTree<T, k>*)rtObject.get())->m_Objects;
  224.         ((BBTree<T, k>*)rtObject.get())->m_IsLeafLevel = m_IsLeafLevel;
  225.         ((BBTree<T, k>*)rtObject.get())->m_Parent = m_Parent;
  226.        
  227.         //insert objects that are true in minimalSplit to ltObjects and false to the rtObjects (they also get assigned their parent if needed)
  228.         for (int i = 0; i < k; ++i)
  229.         {
  230.             if (minimalSplit[i])
  231.             {
  232.                 ltObjects.push_back(m_Objects[i]);
  233.             }
  234.             else
  235.             {
  236.                 rtObjects.push_back(m_Objects[i]);
  237.                 ((BBTree<T, k>*)rtObject.get())->m_TotalBounds += m_Objects[i]->GetBound();
  238.                 if (!m_IsLeafLevel)
  239.                 {
  240.                     ((BBTree<T, k>*)m_Objects[i].get())->m_Parent = ((BBTree<T, k>*)rtObject.get());
  241.                 }
  242.             }
  243.         }
  244.  
  245.  
  246.         // is the root -> current object stays and children are made from the split of the current object
  247.         if (!m_Parent)
  248.         {
  249.             std::shared_ptr<BoundedObject> ltObject(new BBTree<T, k>());
  250.             ((BBTree<T, k>*)ltObject.get())->m_IsLeafLevel = m_IsLeafLevel;
  251.            
  252.             for (auto& object : ltObjects)
  253.             {
  254.                 ((BBTree<T, k>*)ltObject.get())->m_TotalBounds += object->GetBound();
  255.                 if (!m_IsLeafLevel) ((BBTree<T, k>*)object.get())->m_Parent = (BBTree<T, k>*)ltObject.get();
  256.             }
  257.  
  258.             std::swap(((BBTree<T, k>*)ltObject.get())->m_Objects, ltObjects);
  259.  
  260.             // add objects and change their parent
  261.             ((BBTree<T, k>*)rtObject.get())->m_Parent = this;
  262.             ((BBTree<T, k>*)ltObject.get())->m_Parent = this;
  263.             m_Objects.clear();
  264.             m_Objects.push_back(ltObject);
  265.             m_Objects.push_back(rtObject);
  266.             m_IsLeafLevel = false;
  267.         }
  268.         else
  269.         {
  270.             std::swap(m_Objects, ltObjects);
  271.             m_TotalBounds = BoundingBox();
  272.             for (auto& object : m_Objects)
  273.             {
  274.                 m_TotalBounds += object->GetBound();
  275.             }
  276.             m_Parent->m_Objects.push_back(rtObject);
  277.         }
  278.         // is not the root -> current object is split and the leftover objects are moved to a new child to the parent of this object
  279.     }
  280.  
  281.     void FillVolume(std::map<int, float>& totalVolumes, int level = 1)
  282.     {
  283.         for (auto& object : m_Objects)
  284.         {
  285.             totalVolumes[level] += object->GetBound().size();
  286.             if (!m_IsLeafLevel) ((BBTree<T, k>*)object.get())->FillVolume(totalVolumes, level + 1);
  287.         }
  288.     }
  289.    
  290. private:
  291.     std::vector<std::shared_ptr<BoundedObject>> m_Objects;
  292.     BBTree<T, k>* m_Parent;
  293.     bool m_IsLeafLevel;
  294.     BoundingBox m_TotalBounds;
  295. };
  296.  
  297. int main() {
  298.     std::vector<Point> vertices;
  299.     std::ifstream file("teapot.obj");
  300.     std::string c;
  301.    
  302.     BBTree<Polygon, 10> tree;
  303.  
  304.     file >> c;
  305.     while (file) {
  306.         if (c == "v")
  307.         {
  308.             float x;
  309.             float y;
  310.             float z;
  311.             file >> x >> y >> z;
  312.             vertices.push_back({ x, y, z });
  313.         }
  314.         else if (c == "vt")
  315.         {
  316.             while (file && file.peek() != '\n')
  317.             {
  318.                 char s;
  319.                 s = file.get();
  320.             }
  321.         }
  322.         else if (c == "f")
  323.         {
  324.             std::vector<Point> polygon;
  325.             std::string value;
  326.             while (file && file.peek() != '\n')
  327.             {
  328.                 char s;
  329.                 s = file.get();
  330.                 switch (s) {
  331.                 case '\t':
  332.                 case ' ':
  333.                     value.clear();
  334.                     break;
  335.                 case '/':
  336.                 {
  337.                     int idx = std::atoi(value.c_str())-1;
  338.                     polygon.push_back(vertices[idx]);
  339.                     value.clear();
  340.                 }
  341.                     break;
  342.                 default:
  343.                     value += s;
  344.                 }
  345.             }
  346.             tree.add(std::shared_ptr<BoundedObject>(new Polygon(polygon)));
  347.         }
  348.         else
  349.         {
  350.             while (file && file.peek() != '\n')
  351.             {
  352.                 char s;
  353.                 s = file.get();
  354.             }
  355.         }
  356.         file >> c;
  357.     }
  358.     std::map<int, float> levelVolume;
  359.     tree.FillVolume(levelVolume);
  360.     std::cout << "level : totalVolume" << std::endl;
  361.     std::cout << "0 : " << tree.GetBound().size() << std::endl;
  362.     for (auto& levelAndVolume : levelVolume)
  363.     {
  364.         std::cout << levelAndVolume.first << " : " << levelAndVolume.second << std::endl;
  365.     }
  366.  
  367.     return 0;
  368. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement