123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- /*
- 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(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(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(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
|