diff DEPENDENCIES/generic/include/boost/polygon/detail/property_merge.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DEPENDENCIES/generic/include/boost/polygon/detail/property_merge.hpp	Tue Aug 05 11:11:38 2014 +0100
@@ -0,0 +1,588 @@
+/*
+  Copyright 2008 Intel Corporation
+
+  Use, modification and distribution are subject to the Boost Software License,
+  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+  http://www.boost.org/LICENSE_1_0.txt).
+*/
+#ifndef BOOST_POLYGON_PROPERTY_MERGE_HPP
+#define BOOST_POLYGON_PROPERTY_MERGE_HPP
+namespace boost { namespace polygon{
+
+template <typename coordinate_type>
+class property_merge_point {
+private:
+  coordinate_type x_, y_;
+public:
+  inline property_merge_point() : x_(), y_() {}
+  inline property_merge_point(coordinate_type x, coordinate_type y) : x_(x), y_(y) {}
+  //use builtin assign and copy
+  inline bool operator==(const property_merge_point& that) const { return x_ == that.x_ && y_ == that.y_; }
+  inline bool operator!=(const property_merge_point& that) const { return !((*this) == that); }
+  inline bool operator<(const property_merge_point& that) const {
+    if(x_ < that.x_) return true;
+    if(x_ > that.x_) return false;
+    return y_ < that.y_;
+  }
+  inline coordinate_type x() const { return x_; }
+  inline coordinate_type y() const { return y_; }
+  inline void x(coordinate_type value) { x_ = value; }
+  inline void y(coordinate_type value) { y_ = value; }
+};
+
+template <typename coordinate_type>
+class property_merge_interval {
+private:
+  coordinate_type low_, high_;
+public:
+  inline property_merge_interval() : low_(), high_() {}
+  inline property_merge_interval(coordinate_type low, coordinate_type high) : low_(low), high_(high) {}
+  //use builtin assign and copy
+  inline bool operator==(const property_merge_interval& that) const { return low_ == that.low_ && high_ == that.high_; }
+  inline bool operator!=(const property_merge_interval& that) const { return !((*this) == that); }
+  inline bool operator<(const property_merge_interval& that) const {
+    if(low_ < that.low_) return true;
+    if(low_ > that.low_) return false;
+    return high_ < that.high_;
+  }
+  inline coordinate_type low() const { return low_; }
+  inline coordinate_type high() const { return high_; }
+  inline void low(coordinate_type value) { low_ = value; }
+  inline void high(coordinate_type value) { high_ = value; }
+};
+
+template <typename coordinate_type, typename property_type, typename polygon_set_type, typename keytype = std::set<property_type> >
+class merge_scanline {
+public:
+  //definitions
+
+  typedef keytype property_set;
+  typedef std::vector<std::pair<property_type, int> > property_map;
+  typedef std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > vertex_property;
+  typedef std::pair<property_merge_point<coordinate_type>, property_map> vertex_data;
+  typedef std::vector<vertex_property> property_merge_data;
+  //typedef std::map<property_set, polygon_set_type> Result;
+  typedef std::map<coordinate_type, property_map> scanline_type;
+  typedef typename scanline_type::iterator scanline_iterator;
+  typedef std::pair<property_merge_interval<coordinate_type>, std::pair<property_set, property_set> > edge_property;
+  typedef std::vector<edge_property> edge_property_vector;
+
+  //static public member functions
+
+  template <typename iT, typename orientation_2d_type>
+  static inline void
+  populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end,
+                               const property_type& property, orientation_2d_type orient) {
+    for( ; input_begin != input_end; ++input_begin) {
+      std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > element;
+      if(orient == HORIZONTAL)
+        element.first = property_merge_point<coordinate_type>((*input_begin).second.first, (*input_begin).first);
+      else
+        element.first = property_merge_point<coordinate_type>((*input_begin).first, (*input_begin).second.first);
+      element.second.first = property;
+      element.second.second = (*input_begin).second.second;
+      pmd.push_back(element);
+    }
+  }
+
+  //public member functions
+
+  merge_scanline() : output(), scanline(), currentVertex(), tmpVector(), previousY(), countFromBelow(), scanlinePosition() {}
+  merge_scanline(const merge_scanline& that) :
+    output(that.output),
+    scanline(that.scanline),
+    currentVertex(that.currentVertex),
+    tmpVector(that.tmpVector),
+    previousY(that.previousY),
+    countFromBelow(that.countFromBelow),
+    scanlinePosition(that.scanlinePosition)
+  {}
+  merge_scanline& operator=(const merge_scanline& that) {
+    output = that.output;
+    scanline = that.scanline;
+    currentVertex = that.currentVertex;
+    tmpVector = that.tmpVector;
+    previousY = that.previousY;
+    countFromBelow = that.countFromBelow;
+    scanlinePosition = that.scanlinePosition;
+    return *this;
+  }
+
+  template <typename result_type>
+  inline void perform_merge(result_type& result, property_merge_data& data) {
+    if(data.empty()) return;
+    //sort
+    polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>());
+    //scanline
+    bool firstIteration = true;
+    scanlinePosition = scanline.end();
+    for(std::size_t i = 0; i < data.size(); ++i) {
+      if(firstIteration) {
+        mergeProperty(currentVertex.second, data[i].second);
+        currentVertex.first = data[i].first;
+        firstIteration = false;
+      } else {
+        if(data[i].first != currentVertex.first) {
+          if(data[i].first.x() != currentVertex.first.x()) {
+            processVertex(output);
+            //std::cout << scanline.size() << " ";
+            countFromBelow.clear(); //should already be clear
+            writeOutput(currentVertex.first.x(), result, output);
+            currentVertex.second.clear();
+            mergeProperty(currentVertex.second, data[i].second);
+            currentVertex.first = data[i].first;
+            //std::cout << assertRedundant(scanline) << "/" << scanline.size() << " ";
+          } else {
+            processVertex(output);
+            currentVertex.second.clear();
+            mergeProperty(currentVertex.second, data[i].second);
+            currentVertex.first = data[i].first;
+          }
+        } else {
+          mergeProperty(currentVertex.second, data[i].second);
+        }
+      }
+    }
+    processVertex(output);
+    writeOutput(currentVertex.first.x(), result, output);
+    //std::cout << assertRedundant(scanline) << "/" << scanline.size() << "\n";
+    //std::cout << scanline.size() << "\n";
+  }
+
+private:
+  //private supporting types
+
+  template <class T>
+  class less_vertex_data {
+  public:
+    less_vertex_data() {}
+    bool operator()(const T& lvalue, const T& rvalue) const {
+      if(lvalue.first.x() < rvalue.first.x()) return true;
+      if(lvalue.first.x() > rvalue.first.x()) return false;
+      if(lvalue.first.y() < rvalue.first.y()) return true;
+      return false;
+    }
+  };
+
+  template <typename T>
+  struct lessPropertyCount {
+    lessPropertyCount() {}
+    bool operator()(const T& a, const T& b) {
+      return a.first < b.first;
+    }
+  };
+
+  //private static member functions
+
+  static inline void mergeProperty(property_map& lvalue, std::pair<property_type, int>& rvalue) {
+    typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue,
+                                                          lessPropertyCount<std::pair<property_type, int> >());
+    if(itr == lvalue.end() ||
+       (*itr).first != rvalue.first) {
+      lvalue.insert(itr, rvalue);
+    } else {
+      (*itr).second += rvalue.second;
+      if((*itr).second == 0)
+        lvalue.erase(itr);
+    }
+//     if(assertSorted(lvalue)) {
+//       std::cout << "in mergeProperty\n";
+//       exit(0);
+//     }
+  }
+
+//   static inline bool assertSorted(property_map& pset) {
+//     bool result = false;
+//     for(std::size_t i = 1; i < pset.size(); ++i) {
+//       if(pset[i] < pset[i-1]) {
+//         std::cout << "Out of Order Error ";
+//         result = true;
+//       }
+//       if(pset[i].first == pset[i-1].first) {
+//         std::cout << "Duplicate Property Error ";
+//         result = true;
+//       }
+//       if(pset[0].second == 0 || pset[1].second == 0) {
+//         std::cout << "Empty Property Error ";
+//         result = true;
+//       }
+//     }
+//     return result;
+//   }
+
+  static inline void setProperty(property_set& pset, property_map& pmap) {
+    for(typename property_map::iterator itr = pmap.begin(); itr != pmap.end(); ++itr) {
+      if((*itr).second > 0) {
+        pset.insert(pset.end(), (*itr).first);
+      }
+    }
+  }
+
+  //private data members
+
+  edge_property_vector output;
+  scanline_type scanline;
+  vertex_data currentVertex;
+  property_map tmpVector;
+  coordinate_type previousY;
+  property_map countFromBelow;
+  scanline_iterator scanlinePosition;
+
+  //private member functions
+
+  inline void mergeCount(property_map& lvalue, property_map& rvalue) {
+    typename property_map::iterator litr = lvalue.begin();
+    typename property_map::iterator ritr = rvalue.begin();
+    tmpVector.clear();
+    while(litr != lvalue.end() && ritr != rvalue.end()) {
+      if((*litr).first <= (*ritr).first) {
+        if(!tmpVector.empty() &&
+           (*litr).first == tmpVector.back().first) {
+          tmpVector.back().second += (*litr).second;
+        } else {
+          tmpVector.push_back(*litr);
+        }
+        ++litr;
+      } else if((*ritr).first <= (*litr).first) {
+        if(!tmpVector.empty() &&
+           (*ritr).first == tmpVector.back().first) {
+          tmpVector.back().second += (*ritr).second;
+        } else {
+          tmpVector.push_back(*ritr);
+        }
+        ++ritr;
+      }
+    }
+    while(litr != lvalue.end()) {
+      if(!tmpVector.empty() &&
+         (*litr).first == tmpVector.back().first) {
+        tmpVector.back().second += (*litr).second;
+      } else {
+        tmpVector.push_back(*litr);
+      }
+      ++litr;
+    }
+    while(ritr != rvalue.end()) {
+      if(!tmpVector.empty() &&
+         (*ritr).first == tmpVector.back().first) {
+        tmpVector.back().second += (*ritr).second;
+      } else {
+        tmpVector.push_back(*ritr);
+      }
+      ++ritr;
+    }
+    lvalue.clear();
+    for(std::size_t i = 0; i < tmpVector.size(); ++i) {
+      if(tmpVector[i].second != 0) {
+        lvalue.push_back(tmpVector[i]);
+      }
+    }
+//     if(assertSorted(lvalue)) {
+//       std::cout << "in mergeCount\n";
+//       exit(0);
+//     }
+  }
+
+  inline void processVertex(edge_property_vector& output) {
+    if(!countFromBelow.empty()) {
+      //we are processing an interval of change in scanline state between
+      //previous vertex position and current vertex position where
+      //count from below represents the change on the interval
+      //foreach scanline element from previous to current we
+      //write the interval on the scanline that is changing
+      //the old value and the new value to output
+      property_merge_interval<coordinate_type> currentInterval(previousY, currentVertex.first.y());
+      coordinate_type currentY = currentInterval.low();
+      if(scanlinePosition == scanline.end() ||
+         (*scanlinePosition).first != previousY) {
+        scanlinePosition = scanline.lower_bound(previousY);
+      }
+      scanline_iterator previousScanlinePosition = scanlinePosition;
+      ++scanlinePosition;
+      while(scanlinePosition != scanline.end()) {
+        coordinate_type elementY = (*scanlinePosition).first;
+        if(elementY <= currentInterval.high()) {
+          property_map& countOnLeft = (*previousScanlinePosition).second;
+          edge_property element;
+          output.push_back(element);
+          output.back().first = property_merge_interval<coordinate_type>((*previousScanlinePosition).first, elementY);
+          setProperty(output.back().second.first, countOnLeft);
+          mergeCount(countOnLeft, countFromBelow);
+          setProperty(output.back().second.second, countOnLeft);
+          if(output.back().second.first == output.back().second.second) {
+            output.pop_back(); //it was an internal vertical edge, not to be output
+          }
+          else if(output.size() > 1) {
+            edge_property& secondToLast = output[output.size()-2];
+            if(secondToLast.first.high() == output.back().first.low() &&
+               secondToLast.second.first == output.back().second.first &&
+               secondToLast.second.second == output.back().second.second) {
+              //merge output onto previous output because properties are
+              //identical on both sides implying an internal horizontal edge
+              secondToLast.first.high(output.back().first.high());
+              output.pop_back();
+            }
+          }
+          if(previousScanlinePosition == scanline.begin()) {
+            if(countOnLeft.empty()) {
+              scanline.erase(previousScanlinePosition);
+            }
+          } else {
+            scanline_iterator tmpitr = previousScanlinePosition;
+            --tmpitr;
+            if((*tmpitr).second == (*previousScanlinePosition).second)
+              scanline.erase(previousScanlinePosition);
+          }
+
+        } else if(currentY < currentInterval.high()){
+          //elementY > currentInterval.high()
+          //split the interval between previous and current scanline elements
+          std::pair<coordinate_type, property_map> elementScan;
+          elementScan.first = currentInterval.high();
+          elementScan.second = (*previousScanlinePosition).second;
+          scanlinePosition = scanline.insert(scanlinePosition, elementScan);
+          continue;
+        } else {
+          break;
+        }
+        previousScanlinePosition = scanlinePosition;
+        currentY = previousY = elementY;
+        ++scanlinePosition;
+        if(scanlinePosition == scanline.end() &&
+           currentY < currentInterval.high()) {
+          //insert a new element for top of range
+          std::pair<coordinate_type, property_map> elementScan;
+          elementScan.first = currentInterval.high();
+          scanlinePosition = scanline.insert(scanline.end(), elementScan);
+        }
+      }
+      if(scanlinePosition == scanline.end() &&
+         currentY < currentInterval.high()) {
+        //handle case where we iterated to end of the scanline
+        //we need to insert an element into the scanline at currentY
+        //with property value coming from below
+        //and another one at currentInterval.high() with empty property value
+        mergeCount(scanline[currentY], countFromBelow);
+        std::pair<coordinate_type, property_map> elementScan;
+        elementScan.first = currentInterval.high();
+        scanline.insert(scanline.end(), elementScan);
+
+        edge_property element;
+        output.push_back(element);
+        output.back().first = property_merge_interval<coordinate_type>(currentY, currentInterval.high());
+        setProperty(output.back().second.second, countFromBelow);
+        mergeCount(countFromBelow, currentVertex.second);
+      } else {
+        mergeCount(countFromBelow, currentVertex.second);
+        if(countFromBelow.empty()) {
+          if(previousScanlinePosition == scanline.begin()) {
+            if((*previousScanlinePosition).second.empty()) {
+              scanline.erase(previousScanlinePosition);
+              //previousScanlinePosition = scanline.end();
+              //std::cout << "ERASE_A ";
+            }
+          } else {
+            scanline_iterator tmpitr = previousScanlinePosition;
+            --tmpitr;
+            if((*tmpitr).second == (*previousScanlinePosition).second) {
+              scanline.erase(previousScanlinePosition);
+              //previousScanlinePosition = scanline.end();
+              //std::cout << "ERASE_B ";
+            }
+          }
+        }
+      }
+    } else {
+      //count from below is empty, we are starting a new interval of change
+      countFromBelow = currentVertex.second;
+      scanlinePosition = scanline.lower_bound(currentVertex.first.y());
+      if(scanlinePosition != scanline.end()) {
+        if((*scanlinePosition).first != currentVertex.first.y()) {
+          if(scanlinePosition != scanline.begin()) {
+            //decrement to get the lower position of the first interval this vertex intersects
+            --scanlinePosition;
+            //insert a new element into the scanline for the incoming vertex
+            property_map& countOnLeft = (*scanlinePosition).second;
+            std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
+            scanlinePosition = scanline.insert(scanlinePosition, element);
+          } else {
+            property_map countOnLeft;
+            std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
+            scanlinePosition = scanline.insert(scanlinePosition, element);
+          }
+        }
+      } else {
+        property_map countOnLeft;
+        std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
+        scanlinePosition = scanline.insert(scanlinePosition, element);
+      }
+    }
+    previousY = currentVertex.first.y();
+  }
+
+  template <typename T>
+  inline int assertRedundant(T& t) {
+    if(t.empty()) return 0;
+    int count = 0;
+    typename T::iterator itr = t.begin();
+    if((*itr).second.empty())
+      ++count;
+    typename T::iterator itr2 = itr;
+    ++itr2;
+    while(itr2 != t.end()) {
+      if((*itr).second == (*itr2).second)
+        ++count;
+      itr = itr2;
+      ++itr2;
+    }
+    return count;
+  }
+
+  template <typename T>
+  inline void performExtract(T& result, property_merge_data& data) {
+    if(data.empty()) return;
+    //sort
+    polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>());
+
+    //scanline
+    bool firstIteration = true;
+    scanlinePosition = scanline.end();
+    for(std::size_t i = 0; i < data.size(); ++i) {
+      if(firstIteration) {
+        mergeProperty(currentVertex.second, data[i].second);
+        currentVertex.first = data[i].first;
+        firstIteration = false;
+      } else {
+        if(data[i].first != currentVertex.first) {
+          if(data[i].first.x() != currentVertex.first.x()) {
+            processVertex(output);
+            //std::cout << scanline.size() << " ";
+            countFromBelow.clear(); //should already be clear
+            writeGraph(currentVertex.first.x(), result, output, scanline);
+            currentVertex.second.clear();
+            mergeProperty(currentVertex.second, data[i].second);
+            currentVertex.first = data[i].first;
+          } else {
+            processVertex(output);
+            currentVertex.second.clear();
+            mergeProperty(currentVertex.second, data[i].second);
+            currentVertex.first = data[i].first;
+          }
+        } else {
+          mergeProperty(currentVertex.second, data[i].second);
+        }
+      }
+    }
+    processVertex(output);
+    writeGraph(currentVertex.first.x(), result, output, scanline);
+    //std::cout << scanline.size() << "\n";
+  }
+
+  template <typename T>
+  inline void insertEdges(T& graph, property_set& p1, property_set& p2) {
+    for(typename property_set::iterator itr = p1.begin(); itr != p1.end(); ++itr) {
+      for(typename property_set::iterator itr2 = p2.begin(); itr2 != p2.end(); ++itr2) {
+        if(*itr != *itr2) {
+          graph[*itr].insert(*itr2);
+          graph[*itr2].insert(*itr);
+        }
+      }
+    }
+  }
+
+  template <typename T>
+  inline void propertySetAbove(coordinate_type y, property_set& ps, T& scanline) {
+    ps.clear();
+    typename T::iterator itr = scanline.find(y);
+    if(itr != scanline.end())
+      setProperty(ps, (*itr).second);
+  }
+
+  template <typename T>
+  inline void propertySetBelow(coordinate_type y, property_set& ps, T& scanline) {
+    ps.clear();
+    typename T::iterator itr = scanline.find(y);
+    if(itr != scanline.begin()) {
+      --itr;
+      setProperty(ps, (*itr).second);
+    }
+  }
+
+  template <typename T, typename T2>
+  inline void writeGraph(coordinate_type x, T& graph, edge_property_vector& output, T2& scanline) {
+    if(output.empty()) return;
+    edge_property* previousEdgeP = &(output[0]);
+    bool firstIteration = true;
+    property_set ps;
+    for(std::size_t i = 0; i < output.size(); ++i) {
+      edge_property& previousEdge = *previousEdgeP;
+      edge_property& edge = output[i];
+      if(previousEdge.first.high() == edge.first.low()) {
+        //horizontal edge
+        insertEdges(graph, edge.second.first, previousEdge.second.first);
+        //corner 1
+        insertEdges(graph, edge.second.first, previousEdge.second.second);
+        //other horizontal edge
+        insertEdges(graph, edge.second.second, previousEdge.second.second);
+        //corner 2
+        insertEdges(graph, edge.second.second, previousEdge.second.first);
+      } else {
+        if(!firstIteration){
+          //look up regions above previous edge
+          propertySetAbove(previousEdge.first.high(), ps, scanline);
+          insertEdges(graph, ps, previousEdge.second.first);
+          insertEdges(graph, ps, previousEdge.second.second);
+        }
+        //look up regions below current edge in the scanline
+        propertySetBelow(edge.first.high(), ps, scanline);
+        insertEdges(graph, ps, edge.second.first);
+        insertEdges(graph, ps, edge.second.second);
+      }
+      firstIteration = false;
+      //vertical edge
+      insertEdges(graph, edge.second.second, edge.second.first);
+      //shared region to left
+      insertEdges(graph, edge.second.second, edge.second.second);
+      //shared region to right
+      insertEdges(graph, edge.second.first, edge.second.first);
+      previousEdgeP = &(output[i]);
+    }
+    edge_property& previousEdge = *previousEdgeP;
+    propertySetAbove(previousEdge.first.high(), ps, scanline);
+    insertEdges(graph, ps, previousEdge.second.first);
+    insertEdges(graph, ps, previousEdge.second.second);
+    output.clear();
+  }
+
+  template <typename Result>
+  inline void writeOutput(coordinate_type x, Result& result, edge_property_vector& output) {
+    for(std::size_t i = 0; i < output.size(); ++i) {
+      edge_property& edge = output[i];
+      //edge.second.first is the property set on the left of the edge
+      if(!edge.second.first.empty()) {
+        typename Result::iterator itr = result.find(edge.second.first);
+        if(itr == result.end()) {
+          std::pair<property_set, polygon_set_type> element(edge.second.first, polygon_set_type(VERTICAL));
+          itr = result.insert(result.end(), element);
+        }
+        std::pair<interval_data<coordinate_type>, int> element2(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), -1); //right edge of figure
+        (*itr).second.insert(x, element2);
+      }
+      if(!edge.second.second.empty()) {
+        //edge.second.second is the property set on the right of the edge
+        typename Result::iterator itr = result.find(edge.second.second);
+        if(itr == result.end()) {
+          std::pair<property_set, polygon_set_type> element(edge.second.second, polygon_set_type(VERTICAL));
+          itr = result.insert(result.end(), element);
+        }
+        std::pair<interval_data<coordinate_type>, int> element3(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), 1); //left edge of figure
+        (*itr).second.insert(x, element3);
+      }
+    }
+    output.clear();
+  }
+};
+
+}
+}
+#endif