Advertisement
Guest User

quadtree.cpp

a guest
Oct 20th, 2014
389
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.42 KB | None | 0 0
  1. /**
  2.  * @file quadtree.cpp
  3.  * quadtree class implementation.
  4.  * @date Spring 2008
  5.  * @date Modified Summer 2014
  6.  */
  7.  
  8. #include <iostream>
  9. #include <cstdint>
  10. #include <memory>
  11. #include <exception>
  12. #include <cmath>
  13. #include "quadtree.h"
  14. #include "epng.h"
  15. #include "rgba_pixel.h"
  16.  
  17. namespace cs225
  18. {
  19.      /*
  20.       * Constructors for the quadtree class:
  21.       * Defualt constructor
  22.       * Cropped image Constructor
  23.       * Copy constructor
  24.       * Move constructor
  25.       */
  26.  
  27.      quadtree::quadtree()
  28.           :root_{nullptr}, size_{0}
  29.      {
  30.           //Call the defualt node constructor
  31.           node();
  32.      }
  33.  
  34.      quadtree::quadtree(const epng::png& source, uint64_t resolution)
  35.            :root_{nullptr}, size_{0}
  36.      {
  37.           //Build_tree will initialize and construct the tree    
  38.           build_tree(source, resolution);
  39.      }
  40.  
  41.      quadtree::quadtree(const quadtree& other)
  42.           :root_{nullptr}, size_{other.size_}
  43.      {
  44.           //Check if other is empty
  45.           if(other.root_ != nullptr)
  46.                root_ = std::make_unique<node>(node(*(other.root_.get())));
  47.      }
  48.  
  49.      quadtree::quadtree(quadtree&& other)
  50.           :root_{nullptr}, size_{0}
  51.      {
  52.           std::swap(root_, other.root_);
  53.           std::swap(size_, other.size_);
  54.      }
  55.  
  56.      /*
  57.       * Constructors for the node structures:
  58.       * Defualt constructor
  59.       * Copy constructor
  60.       */
  61.  
  62.      quadtree::node::node()
  63.           :northwest{nullptr}, northeast{nullptr},
  64.            southwest{nullptr}, southeast{nullptr},
  65.            element{epng::rgba_pixel()}
  66.      {
  67.           //Nothing!
  68.      }
  69.  
  70.      quadtree::node::node(const node& other)
  71.           :northwest{nullptr}, northeast{nullptr},
  72.            southwest{nullptr}, southeast{nullptr},
  73.            element{epng::rgba_pixel()}
  74.      {
  75.           //Copy over all the nodes and elements
  76.           element = std::move(copy_nodes(other));
  77.      }
  78.  
  79.      quadtree& quadtree::operator=(quadtree other)
  80.      {
  81.           if(root_ != nullptr)
  82.           {
  83.                clear(*(root_.get()));
  84.                root_.reset(nullptr);
  85.           }
  86.           size_ = std::move(other.size_);
  87.           swap(other);
  88.           return *this;
  89.      }
  90.  
  91.      const epng::rgba_pixel& quadtree::operator()(uint64_t x, uint64_t y) const
  92.      {
  93.           uint64_t x_bound = size_;
  94.           uint64_t y_bound = size_;
  95.           epng::rgba_pixel temp = epng::rgba_pixel();
  96.  
  97.           //Check the bounds of the given coordinates
  98.           if(!root_)
  99.                throw std::out_of_range("Empty tree");
  100.           else if(x > (size_-1) || y > (size_-1))
  101.                throw std::out_of_range("Invalid coordinates");
  102.  
  103.           //Call the helper function to return the pixel
  104.           return find_pixel(*(root_.get()), temp, x, y, x_bound, y_bound);
  105.      }
  106.  
  107.      void quadtree::build_tree(const epng::png& source, uint64_t resolution)
  108.      {
  109.           uint64_t height = 0;
  110.           uint64_t level = 0;
  111.           uint64_t x = 0;
  112.           uint64_t y = 0;
  113.           uint64_t iter_x = 0;
  114.           uint64_t iter_y = 0;
  115.           int base = 0;
  116.  
  117.           if(root_ != nullptr)
  118.           {
  119.                //Delete the contents of the current tree
  120.                clear(*(root_.get()));
  121.                root_ = nullptr;
  122.           }
  123.  
  124.           //Set the size of the quadtree
  125.           size_ = resolution;
  126.  
  127.           //Compute the height of the tree to be built
  128.           height = log2(resolution);
  129.  
  130.           //Create the root for the tree
  131.           root_ = std::make_unique<node>(node());
  132.  
  133.           //build the tree by looping through the pixels recursively
  134.           build_tree(source, resolution, *(root_.get()), level, height, x, y, iter_x, iter_y, base);
  135.      }
  136.  
  137.      epng::png quadtree::decompress() const
  138.      {
  139.           //Check for an empty tree
  140.           if(!root_)
  141.                throw std::runtime_error("Empty tree");
  142.  
  143.           //Create the png image from the quadtree
  144.           epng::png* out_png = new epng::png(size_, size_);
  145.           epng::png temp_png = epng::png(size_, size_);
  146.  
  147.           uint64_t height = log2(size_);
  148.  
  149.           //Set each pixel to its respective pixel in the quadtree
  150.           *out_png = get_pixels(*(root_.get()), temp_png, size_, size_, height+1);
  151.  
  152.           return *out_png;
  153.      }
  154.  
  155.      void quadtree::rotate_clockwise()
  156.      {
  157.           //Call the helper function
  158.           rotate_clockwise(*(root_.get()));
  159.          
  160.      }
  161.  
  162.      void quadtree::clear(node& subroot)
  163.      {
  164.           //Perform a depth-first deletion of the tree
  165.           //Base case: At a leaf
  166.           if(!subroot.northwest.get() && !subroot.northeast.get() && !subroot.southwest.get() && !subroot.southeast.get())
  167.           {
  168.                return;
  169.           }
  170.  
  171.           //Traverse the Northwest child
  172.           if(subroot.northwest.get() != nullptr)
  173.           {
  174.                clear(*(subroot.northwest.get()));
  175.                subroot.northwest.reset(nullptr);
  176.           }
  177.  
  178.           //Traverse the Northeast child
  179.           if(subroot.northeast.get() != nullptr)
  180.           {
  181.                clear(*(subroot.northeast.get()));
  182.                subroot.northeast.reset(nullptr);
  183.           }
  184.  
  185.           //Traverse the Southwest child
  186.           if(subroot.southwest.get() != nullptr)
  187.           {
  188.                clear(*(subroot.southwest.get()));
  189.                subroot.southwest.reset(nullptr);
  190.           }
  191.  
  192.           //Traverse the Southeast child
  193.           if(subroot.southeast.get() != nullptr)
  194.           {
  195.                clear(*(subroot.southeast.get()));
  196.                subroot.southeast.reset(nullptr);
  197.           }
  198.  
  199.           return;
  200.      }
  201.  
  202.      void quadtree::swap(quadtree& other)
  203.      {
  204.           //Call the copy_nodes function to copy the nodes
  205.           root_ = std::make_unique<node>(node(*(other.root_.get())));
  206.      }
  207.  
  208.      void quadtree::build_tree(const epng::png source, const uint64_t scope, node& subroot, uint64_t level,
  209.                                const uint64_t height, uint64_t x, uint64_t y, uint64_t iter_x, uint64_t iter_y, int& base)
  210.      {
  211.           if(base == pow(scope, 2))
  212.                return;
  213.  
  214.           iter_x = x;
  215.           iter_y = y;
  216.  
  217.           //Base case: At a  leaf
  218.           if(level == height)
  219.           {
  220.                base++;
  221.  
  222.                //Get the element
  223.                subroot.element = std::move(*source(x+iter_x, y+iter_y));
  224.  
  225.                if(iter_x == 1)
  226.                {
  227.                     iter_x = 0;
  228.                     if(iter_y == 1)
  229.                          iter_y = 0;
  230.                     else
  231.                          iter_y++;
  232.                }
  233.                else
  234.                     iter_x++;
  235.                
  236.                return;
  237.           }
  238.  
  239.           //Perform a breadth-first like build of the tree
  240.           subroot.northwest = std::make_unique<node>(node());
  241.           subroot.northeast = std::make_unique<node>(node());
  242.           subroot.southwest = std::make_unique<node>(node());
  243.           subroot.southeast = std::make_unique<node>(node());
  244.  
  245.           level++;
  246.  
  247.           //recursively call the the subroots
  248.           build_tree(source, scope, *(subroot.northwest.get()), level, height, x, y, iter_x, iter_y, base);
  249.           build_tree(source, scope, *(subroot.northeast.get()), level, height, (x+(level/2)), y, iter_x, iter_y, base);
  250.           build_tree(source, scope, *(subroot.southwest.get()), level, height, x, (y+(level/2)), iter_x, iter_y, base);
  251.           build_tree(source, scope, *(subroot.southeast.get()), level, height, (x+(level/2)), (y+(level/2)), iter_x, iter_y, base);
  252.  
  253.           //Compute the average of the colors
  254.           subroot.element.red = (subroot.northwest.get()->element.red + subroot.northeast.get()->element.red +
  255.                                  subroot.southwest.get()->element.red + subroot.southeast.get()->element.red)/4;
  256.           subroot.element.green = (subroot.northwest.get()->element.green + subroot.northeast.get()->element.green +
  257.                                  subroot.southwest.get()->element.green + subroot.southeast.get()->element.green)/4;
  258.           subroot.element.blue = (subroot.northwest.get()->element.blue + subroot.northeast.get()->element.blue +
  259.                                  subroot.southwest.get()->element.blue + subroot.southeast.get()->element.blue)/4;
  260.           subroot.element.alpha = (subroot.northwest.get()->element.alpha + subroot.northeast.get()->element.alpha +
  261.                                  subroot.southwest.get()->element.alpha + subroot.southeast.get()->element.alpha)/4;
  262.           return;
  263.      }
  264.  
  265.      const epng::rgba_pixel& quadtree::find_pixel(node& subroot, epng::rgba_pixel& temp, const uint64_t x, const uint64_t y,
  266.                                                   uint64_t x_bound, uint64_t y_bound) const
  267.      {
  268.           //Base case: At a leaf
  269.           if(!subroot.northwest.get() && !subroot.northeast.get() && !subroot.southwest.get() && !subroot.southeast.get())
  270.           {
  271.                temp = subroot.element;
  272.                return temp;
  273.           }
  274.           if(x >= (x_bound/2))
  275.           {
  276.                if(y >= (y_bound/2))
  277.                {
  278.                     //Pixel is in the southeast node
  279.                     temp = find_pixel(*(subroot.southeast.get()), temp, x, y, (x_bound+2), (y_bound+2));
  280.                }
  281.                else
  282.                {
  283.                     //Pixel is in the northeast node
  284.                     temp = find_pixel(*(subroot.northeast.get()), temp, x, y, (x_bound+2), (y_bound/2));
  285.                }
  286.           }
  287.           else
  288.           {
  289.                if(y >= (y_bound/2))
  290.                {
  291.                     //Pixel is in the southwest node
  292.                     temp = find_pixel(*(subroot.southwest.get()), temp, x, y, (x_bound/2), (y_bound+2));
  293.                }
  294.                else
  295.                {
  296.                     //Pixel is in the northwest node
  297.                     temp = find_pixel(*(subroot.northwest.get()), temp, x, y, (x_bound/2), (y_bound/2));
  298.                }
  299.           }
  300.  
  301.           return temp;
  302.      }
  303.  
  304.      const epng::png& quadtree::get_pixels(const node& subroot, epng::png& out_png, uint64_t x, uint64_t y, uint64_t level) const
  305.      {
  306.           //Base case: At a leaf
  307.           if(!subroot.northwest.get() && !subroot.northeast.get() && !subroot.southwest.get() && !subroot.southeast.get())
  308.           {
  309.                *out_png(x-1, y-1) = subroot.element;
  310.                return out_png;
  311.           }
  312.  
  313.           level--;
  314.  
  315.           //Traverse the northwest node
  316.           if(subroot.northwest.get() != nullptr)
  317.                get_pixels(*(subroot.northwest.get()), out_png, ceil(x/2), ceil(y/2), level);
  318.  
  319.           //Traverse the northeast node
  320.           if(subroot.northeast.get() != nullptr)
  321.                get_pixels(*(subroot.northeast.get()), out_png, ceil(x/2+level), ceil(y/2), level);
  322.  
  323.           //Traverse the southwest node
  324.           if(subroot.southwest.get() != nullptr)
  325.                get_pixels(*(subroot.southwest.get()), out_png, ceil(x/2), ceil(y/2+level),level);
  326.  
  327.           //Traverse the southeast node
  328.           if(subroot.southeast.get() != nullptr)
  329.                get_pixels(*(subroot.southeast.get()), out_png, ceil(x/2+level), ceil(y/2+level), level);
  330.  
  331.           return out_png;
  332.      }
  333.  
  334.      const epng::rgba_pixel& quadtree::node::copy_nodes(const node& other)
  335.      {
  336.           //Base case: At a leaf
  337.           if(!other.northwest.get() && !other.northeast.get() && !other.southwest.get() && !other.southeast.get())
  338.           {
  339.                return other.element;
  340.           }
  341.  
  342.           //Traverse the northwest node
  343.           if(other.northwest.get() != nullptr)
  344.           {
  345.                //Create a node at the child
  346.                this->northwest = std::make_unique<node>(node(*(other.northwest.get())));
  347.           }
  348.  
  349.           //Traverse the northeast node
  350.           if(other.northeast.get() != nullptr)
  351.           {
  352.                //Create a node at the child
  353.                this->northeast = std::make_unique<node>(node(*(other.northeast.get())));
  354.           }
  355.  
  356.           //Traverse the southwest node
  357.           if(other.southwest.get() != nullptr)
  358.           {
  359.                //Create a node at the child
  360.                this->southwest = std::make_unique<node>(node(*(other.southwest.get())));
  361.           }
  362.  
  363.           //Traverse the southeast node
  364.           if(other.southeast.get() != nullptr)
  365.           {
  366.                //Create a node at the child
  367.                this->southeast = std::make_unique<node>(node(*(other.southeast.get())));
  368.           }
  369.  
  370.           return other.element;
  371.      }
  372.  
  373.      void quadtree::rotate_clockwise(node& subroot)
  374.      {
  375.           //Base case: At a leaf
  376.           if(!subroot.northwest.get() && !subroot.northeast.get() && !subroot.southwest.get() && !subroot.southeast.get())
  377.           {
  378.                return;
  379.           }
  380.  
  381.           //Traverse the northwest node
  382.           if(subroot.northwest != nullptr)
  383.           {
  384.                rotate_clockwise(*(subroot.northwest.get()));
  385.  
  386.                //Rotate the nodes
  387.                std::swap(subroot.northwest, subroot.southeast);
  388.                std::swap(subroot.northwest, subroot.southwest);
  389.                std::swap(subroot.northwest, subroot.northeast);
  390.           }
  391.  
  392.           //Traverse the northeast node
  393.           if(subroot.northeast != nullptr)
  394.           {
  395.                rotate_clockwise(*(subroot.northeast.get()));
  396.  
  397.                //Rotate the nodes
  398.                std::swap(subroot.northwest, subroot.southeast);
  399.                std::swap(subroot.northwest, subroot.southwest);
  400.                std::swap(subroot.northwest, subroot.northeast);
  401.           }
  402.  
  403.           //Traverse the southwest node
  404.           if(subroot.southwest != nullptr)
  405.           {
  406.                rotate_clockwise(*(subroot.southwest.get()));
  407.  
  408.                //Rotate the nodes
  409.                std::swap(subroot.northwest, subroot.southeast);
  410.                std::swap(subroot.northwest, subroot.southwest);
  411.                std::swap(subroot.northwest, subroot.northeast);
  412.           }
  413.  
  414.           //Traverse the southeast node
  415.           if(subroot.southwest != nullptr)
  416.           {
  417.                rotate_clockwise(*(subroot.southeast.get()));
  418.  
  419.                //Rotate the nodes
  420.                std::swap(subroot.northwest, subroot.southeast);
  421.                std::swap(subroot.northwest, subroot.southwest);
  422.                std::swap(subroot.northwest, subroot.northeast);
  423.           }
  424.      }
  425. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement