Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 10:04:21

0001 /*
0002   Copyright 2008 Intel Corporation
0003 
0004   Use, modification and distribution are subject to the Boost Software License,
0005   Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0006   http://www.boost.org/LICENSE_1_0.txt).
0007 */
0008 #ifndef BOOST_POLYGON_PROPERTY_MERGE_HPP
0009 #define BOOST_POLYGON_PROPERTY_MERGE_HPP
0010 namespace boost { namespace polygon{
0011 
0012 template <typename coordinate_type>
0013 class property_merge_point {
0014 private:
0015   coordinate_type x_, y_;
0016 public:
0017   inline property_merge_point() : x_(), y_() {}
0018   inline property_merge_point(coordinate_type x, coordinate_type y) : x_(x), y_(y) {}
0019   //use builtin assign and copy
0020   inline bool operator==(const property_merge_point& that) const { return x_ == that.x_ && y_ == that.y_; }
0021   inline bool operator!=(const property_merge_point& that) const { return !((*this) == that); }
0022   inline bool operator<(const property_merge_point& that) const {
0023     if(x_ < that.x_) return true;
0024     if(x_ > that.x_) return false;
0025     return y_ < that.y_;
0026   }
0027   inline coordinate_type x() const { return x_; }
0028   inline coordinate_type y() const { return y_; }
0029   inline void x(coordinate_type value) { x_ = value; }
0030   inline void y(coordinate_type value) { y_ = value; }
0031 };
0032 
0033 template <typename coordinate_type>
0034 class property_merge_interval {
0035 private:
0036   coordinate_type low_, high_;
0037 public:
0038   inline property_merge_interval() : low_(), high_() {}
0039   inline property_merge_interval(coordinate_type low, coordinate_type high) : low_(low), high_(high) {}
0040   //use builtin assign and copy
0041   inline bool operator==(const property_merge_interval& that) const { return low_ == that.low_ && high_ == that.high_; }
0042   inline bool operator!=(const property_merge_interval& that) const { return !((*this) == that); }
0043   inline bool operator<(const property_merge_interval& that) const {
0044     if(low_ < that.low_) return true;
0045     if(low_ > that.low_) return false;
0046     return high_ < that.high_;
0047   }
0048   inline coordinate_type low() const { return low_; }
0049   inline coordinate_type high() const { return high_; }
0050   inline void low(coordinate_type value) { low_ = value; }
0051   inline void high(coordinate_type value) { high_ = value; }
0052 };
0053 
0054 template <typename coordinate_type, typename property_type, typename polygon_set_type, typename keytype = std::set<property_type> >
0055 class merge_scanline {
0056 public:
0057   //definitions
0058 
0059   typedef keytype property_set;
0060   typedef std::vector<std::pair<property_type, int> > property_map;
0061   typedef std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > vertex_property;
0062   typedef std::pair<property_merge_point<coordinate_type>, property_map> vertex_data;
0063   typedef std::vector<vertex_property> property_merge_data;
0064   //typedef std::map<property_set, polygon_set_type> Result;
0065   typedef std::map<coordinate_type, property_map> scanline_type;
0066   typedef typename scanline_type::iterator scanline_iterator;
0067   typedef std::pair<property_merge_interval<coordinate_type>, std::pair<property_set, property_set> > edge_property;
0068   typedef std::vector<edge_property> edge_property_vector;
0069 
0070   //static public member functions
0071 
0072   template <typename iT, typename orientation_2d_type>
0073   static inline void
0074   populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end,
0075                                const property_type& property, orientation_2d_type orient) {
0076     for( ; input_begin != input_end; ++input_begin) {
0077       std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > element;
0078       if(orient == HORIZONTAL)
0079         element.first = property_merge_point<coordinate_type>((*input_begin).second.first, (*input_begin).first);
0080       else
0081         element.first = property_merge_point<coordinate_type>((*input_begin).first, (*input_begin).second.first);
0082       element.second.first = property;
0083       element.second.second = (*input_begin).second.second;
0084       pmd.push_back(element);
0085     }
0086   }
0087 
0088   //public member functions
0089 
0090   merge_scanline() : output(), scanline(), currentVertex(), tmpVector(), previousY(), countFromBelow(), scanlinePosition() {}
0091   merge_scanline(const merge_scanline& that) :
0092     output(that.output),
0093     scanline(that.scanline),
0094     currentVertex(that.currentVertex),
0095     tmpVector(that.tmpVector),
0096     previousY(that.previousY),
0097     countFromBelow(that.countFromBelow),
0098     scanlinePosition(that.scanlinePosition)
0099   {}
0100   merge_scanline& operator=(const merge_scanline& that) {
0101     output = that.output;
0102     scanline = that.scanline;
0103     currentVertex = that.currentVertex;
0104     tmpVector = that.tmpVector;
0105     previousY = that.previousY;
0106     countFromBelow = that.countFromBelow;
0107     scanlinePosition = that.scanlinePosition;
0108     return *this;
0109   }
0110 
0111   template <typename result_type>
0112   inline void perform_merge(result_type& result, property_merge_data& data) {
0113     if(data.empty()) return;
0114     //sort
0115     polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>());
0116     //scanline
0117     bool firstIteration = true;
0118     scanlinePosition = scanline.end();
0119     for(std::size_t i = 0; i < data.size(); ++i) {
0120       if(firstIteration) {
0121         mergeProperty(currentVertex.second, data[i].second);
0122         currentVertex.first = data[i].first;
0123         firstIteration = false;
0124       } else {
0125         if(data[i].first != currentVertex.first) {
0126           if(data[i].first.x() != currentVertex.first.x()) {
0127             processVertex(output);
0128             //std::cout << scanline.size() << " ";
0129             countFromBelow.clear(); //should already be clear
0130             writeOutput(currentVertex.first.x(), result, output);
0131             currentVertex.second.clear();
0132             mergeProperty(currentVertex.second, data[i].second);
0133             currentVertex.first = data[i].first;
0134             //std::cout << assertRedundant(scanline) << "/" << scanline.size() << " ";
0135           } else {
0136             processVertex(output);
0137             currentVertex.second.clear();
0138             mergeProperty(currentVertex.second, data[i].second);
0139             currentVertex.first = data[i].first;
0140           }
0141         } else {
0142           mergeProperty(currentVertex.second, data[i].second);
0143         }
0144       }
0145     }
0146     processVertex(output);
0147     writeOutput(currentVertex.first.x(), result, output);
0148     //std::cout << assertRedundant(scanline) << "/" << scanline.size() << "\n";
0149     //std::cout << scanline.size() << "\n";
0150   }
0151 
0152 private:
0153   //private supporting types
0154 
0155   template <class T>
0156   class less_vertex_data {
0157   public:
0158     less_vertex_data() {}
0159     bool operator()(const T& lvalue, const T& rvalue) const {
0160       if(lvalue.first.x() < rvalue.first.x()) return true;
0161       if(lvalue.first.x() > rvalue.first.x()) return false;
0162       if(lvalue.first.y() < rvalue.first.y()) return true;
0163       return false;
0164     }
0165   };
0166 
0167   template <typename T>
0168   struct lessPropertyCount {
0169     lessPropertyCount() {}
0170     bool operator()(const T& a, const T& b) {
0171       return a.first < b.first;
0172     }
0173   };
0174 
0175   //private static member functions
0176 
0177   static inline void mergeProperty(property_map& lvalue, std::pair<property_type, int>& rvalue) {
0178     typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue,
0179                                                           lessPropertyCount<std::pair<property_type, int> >());
0180     if(itr == lvalue.end() ||
0181        (*itr).first != rvalue.first) {
0182       lvalue.insert(itr, rvalue);
0183     } else {
0184       (*itr).second += rvalue.second;
0185       if((*itr).second == 0)
0186         lvalue.erase(itr);
0187     }
0188 //     if(assertSorted(lvalue)) {
0189 //       std::cout << "in mergeProperty\n";
0190 //       exit(0);
0191 //     }
0192   }
0193 
0194 //   static inline bool assertSorted(property_map& pset) {
0195 //     bool result = false;
0196 //     for(std::size_t i = 1; i < pset.size(); ++i) {
0197 //       if(pset[i] < pset[i-1]) {
0198 //         std::cout << "Out of Order Error ";
0199 //         result = true;
0200 //       }
0201 //       if(pset[i].first == pset[i-1].first) {
0202 //         std::cout << "Duplicate Property Error ";
0203 //         result = true;
0204 //       }
0205 //       if(pset[0].second == 0 || pset[1].second == 0) {
0206 //         std::cout << "Empty Property Error ";
0207 //         result = true;
0208 //       }
0209 //     }
0210 //     return result;
0211 //   }
0212 
0213   static inline void setProperty(property_set& pset, property_map& pmap) {
0214     for(typename property_map::iterator itr = pmap.begin(); itr != pmap.end(); ++itr) {
0215       if((*itr).second > 0) {
0216         pset.insert(pset.end(), (*itr).first);
0217       }
0218     }
0219   }
0220 
0221   //private data members
0222 
0223   edge_property_vector output;
0224   scanline_type scanline;
0225   vertex_data currentVertex;
0226   property_map tmpVector;
0227   coordinate_type previousY;
0228   property_map countFromBelow;
0229   scanline_iterator scanlinePosition;
0230 
0231   //private member functions
0232 
0233   inline void mergeCount(property_map& lvalue, property_map& rvalue) {
0234     typename property_map::iterator litr = lvalue.begin();
0235     typename property_map::iterator ritr = rvalue.begin();
0236     tmpVector.clear();
0237     while(litr != lvalue.end() && ritr != rvalue.end()) {
0238       if((*litr).first <= (*ritr).first) {
0239         if(!tmpVector.empty() &&
0240            (*litr).first == tmpVector.back().first) {
0241           tmpVector.back().second += (*litr).second;
0242         } else {
0243           tmpVector.push_back(*litr);
0244         }
0245         ++litr;
0246       } else if((*ritr).first <= (*litr).first) {
0247         if(!tmpVector.empty() &&
0248            (*ritr).first == tmpVector.back().first) {
0249           tmpVector.back().second += (*ritr).second;
0250         } else {
0251           tmpVector.push_back(*ritr);
0252         }
0253         ++ritr;
0254       }
0255     }
0256     while(litr != lvalue.end()) {
0257       if(!tmpVector.empty() &&
0258          (*litr).first == tmpVector.back().first) {
0259         tmpVector.back().second += (*litr).second;
0260       } else {
0261         tmpVector.push_back(*litr);
0262       }
0263       ++litr;
0264     }
0265     while(ritr != rvalue.end()) {
0266       if(!tmpVector.empty() &&
0267          (*ritr).first == tmpVector.back().first) {
0268         tmpVector.back().second += (*ritr).second;
0269       } else {
0270         tmpVector.push_back(*ritr);
0271       }
0272       ++ritr;
0273     }
0274     lvalue.clear();
0275     for(std::size_t i = 0; i < tmpVector.size(); ++i) {
0276       if(tmpVector[i].second != 0) {
0277         lvalue.push_back(tmpVector[i]);
0278       }
0279     }
0280 //     if(assertSorted(lvalue)) {
0281 //       std::cout << "in mergeCount\n";
0282 //       exit(0);
0283 //     }
0284   }
0285 
0286   inline void processVertex(edge_property_vector& output) {
0287     if(!countFromBelow.empty()) {
0288       //we are processing an interval of change in scanline state between
0289       //previous vertex position and current vertex position where
0290       //count from below represents the change on the interval
0291       //foreach scanline element from previous to current we
0292       //write the interval on the scanline that is changing
0293       //the old value and the new value to output
0294       property_merge_interval<coordinate_type> currentInterval(previousY, currentVertex.first.y());
0295       coordinate_type currentY = currentInterval.low();
0296       if(scanlinePosition == scanline.end() ||
0297          (*scanlinePosition).first != previousY) {
0298         scanlinePosition = scanline.lower_bound(previousY);
0299       }
0300       scanline_iterator previousScanlinePosition = scanlinePosition;
0301       ++scanlinePosition;
0302       while(scanlinePosition != scanline.end()) {
0303         coordinate_type elementY = (*scanlinePosition).first;
0304         if(elementY <= currentInterval.high()) {
0305           property_map& countOnLeft = (*previousScanlinePosition).second;
0306           edge_property element;
0307           output.push_back(element);
0308           output.back().first = property_merge_interval<coordinate_type>((*previousScanlinePosition).first, elementY);
0309           setProperty(output.back().second.first, countOnLeft);
0310           mergeCount(countOnLeft, countFromBelow);
0311           setProperty(output.back().second.second, countOnLeft);
0312           if(output.back().second.first == output.back().second.second) {
0313             output.pop_back(); //it was an internal vertical edge, not to be output
0314           }
0315           else if(output.size() > 1) {
0316             edge_property& secondToLast = output[output.size()-2];
0317             if(secondToLast.first.high() == output.back().first.low() &&
0318                secondToLast.second.first == output.back().second.first &&
0319                secondToLast.second.second == output.back().second.second) {
0320               //merge output onto previous output because properties are
0321               //identical on both sides implying an internal horizontal edge
0322               secondToLast.first.high(output.back().first.high());
0323               output.pop_back();
0324             }
0325           }
0326           if(previousScanlinePosition == scanline.begin()) {
0327             if(countOnLeft.empty()) {
0328               scanline.erase(previousScanlinePosition);
0329             }
0330           } else {
0331             scanline_iterator tmpitr = previousScanlinePosition;
0332             --tmpitr;
0333             if((*tmpitr).second == (*previousScanlinePosition).second)
0334               scanline.erase(previousScanlinePosition);
0335           }
0336 
0337         } else if(currentY < currentInterval.high()){
0338           //elementY > currentInterval.high()
0339           //split the interval between previous and current scanline elements
0340           std::pair<coordinate_type, property_map> elementScan;
0341           elementScan.first = currentInterval.high();
0342           elementScan.second = (*previousScanlinePosition).second;
0343           scanlinePosition = scanline.insert(scanlinePosition, elementScan);
0344           continue;
0345         } else {
0346           break;
0347         }
0348         previousScanlinePosition = scanlinePosition;
0349         currentY = previousY = elementY;
0350         ++scanlinePosition;
0351         if(scanlinePosition == scanline.end() &&
0352            currentY < currentInterval.high()) {
0353           //insert a new element for top of range
0354           std::pair<coordinate_type, property_map> elementScan;
0355           elementScan.first = currentInterval.high();
0356           scanlinePosition = scanline.insert(scanline.end(), elementScan);
0357         }
0358       }
0359       if(scanlinePosition == scanline.end() &&
0360          currentY < currentInterval.high()) {
0361         //handle case where we iterated to end of the scanline
0362         //we need to insert an element into the scanline at currentY
0363         //with property value coming from below
0364         //and another one at currentInterval.high() with empty property value
0365         mergeCount(scanline[currentY], countFromBelow);
0366         std::pair<coordinate_type, property_map> elementScan;
0367         elementScan.first = currentInterval.high();
0368         scanline.insert(scanline.end(), elementScan);
0369 
0370         edge_property element;
0371         output.push_back(element);
0372         output.back().first = property_merge_interval<coordinate_type>(currentY, currentInterval.high());
0373         setProperty(output.back().second.second, countFromBelow);
0374         mergeCount(countFromBelow, currentVertex.second);
0375       } else {
0376         mergeCount(countFromBelow, currentVertex.second);
0377         if(countFromBelow.empty()) {
0378           if(previousScanlinePosition == scanline.begin()) {
0379             if((*previousScanlinePosition).second.empty()) {
0380               scanline.erase(previousScanlinePosition);
0381               //previousScanlinePosition = scanline.end();
0382               //std::cout << "ERASE_A ";
0383             }
0384           } else {
0385             scanline_iterator tmpitr = previousScanlinePosition;
0386             --tmpitr;
0387             if((*tmpitr).second == (*previousScanlinePosition).second) {
0388               scanline.erase(previousScanlinePosition);
0389               //previousScanlinePosition = scanline.end();
0390               //std::cout << "ERASE_B ";
0391             }
0392           }
0393         }
0394       }
0395     } else {
0396       //count from below is empty, we are starting a new interval of change
0397       countFromBelow = currentVertex.second;
0398       scanlinePosition = scanline.lower_bound(currentVertex.first.y());
0399       if(scanlinePosition != scanline.end()) {
0400         if((*scanlinePosition).first != currentVertex.first.y()) {
0401           if(scanlinePosition != scanline.begin()) {
0402             //decrement to get the lower position of the first interval this vertex intersects
0403             --scanlinePosition;
0404             //insert a new element into the scanline for the incoming vertex
0405             property_map& countOnLeft = (*scanlinePosition).second;
0406             std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
0407             scanlinePosition = scanline.insert(scanlinePosition, element);
0408           } else {
0409             property_map countOnLeft;
0410             std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
0411             scanlinePosition = scanline.insert(scanlinePosition, element);
0412           }
0413         }
0414       } else {
0415         property_map countOnLeft;
0416         std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
0417         scanlinePosition = scanline.insert(scanlinePosition, element);
0418       }
0419     }
0420     previousY = currentVertex.first.y();
0421   }
0422 
0423   template <typename T>
0424   inline int assertRedundant(T& t) {
0425     if(t.empty()) return 0;
0426     int count = 0;
0427     typename T::iterator itr = t.begin();
0428     if((*itr).second.empty())
0429       ++count;
0430     typename T::iterator itr2 = itr;
0431     ++itr2;
0432     while(itr2 != t.end()) {
0433       if((*itr).second == (*itr2).second)
0434         ++count;
0435       itr = itr2;
0436       ++itr2;
0437     }
0438     return count;
0439   }
0440 
0441   template <typename T>
0442   inline void performExtract(T& result, property_merge_data& data) {
0443     if(data.empty()) return;
0444     //sort
0445     polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>());
0446 
0447     //scanline
0448     bool firstIteration = true;
0449     scanlinePosition = scanline.end();
0450     for(std::size_t i = 0; i < data.size(); ++i) {
0451       if(firstIteration) {
0452         mergeProperty(currentVertex.second, data[i].second);
0453         currentVertex.first = data[i].first;
0454         firstIteration = false;
0455       } else {
0456         if(data[i].first != currentVertex.first) {
0457           if(data[i].first.x() != currentVertex.first.x()) {
0458             processVertex(output);
0459             //std::cout << scanline.size() << " ";
0460             countFromBelow.clear(); //should already be clear
0461             writeGraph(result, output, scanline);
0462             currentVertex.second.clear();
0463             mergeProperty(currentVertex.second, data[i].second);
0464             currentVertex.first = data[i].first;
0465           } else {
0466             processVertex(output);
0467             currentVertex.second.clear();
0468             mergeProperty(currentVertex.second, data[i].second);
0469             currentVertex.first = data[i].first;
0470           }
0471         } else {
0472           mergeProperty(currentVertex.second, data[i].second);
0473         }
0474       }
0475     }
0476     processVertex(output);
0477     writeGraph(result, output, scanline);
0478     //std::cout << scanline.size() << "\n";
0479   }
0480 
0481   template <typename T>
0482   inline void insertEdges(T& graph, property_set& p1, property_set& p2) {
0483     for(typename property_set::iterator itr = p1.begin(); itr != p1.end(); ++itr) {
0484       for(typename property_set::iterator itr2 = p2.begin(); itr2 != p2.end(); ++itr2) {
0485         if(*itr != *itr2) {
0486           graph[*itr].insert(*itr2);
0487           graph[*itr2].insert(*itr);
0488         }
0489       }
0490     }
0491   }
0492 
0493   template <typename T>
0494   inline void propertySetAbove(coordinate_type y, property_set& ps, T& scanline) {
0495     ps.clear();
0496     typename T::iterator itr = scanline.find(y);
0497     if(itr != scanline.end())
0498       setProperty(ps, (*itr).second);
0499   }
0500 
0501   template <typename T>
0502   inline void propertySetBelow(coordinate_type y, property_set& ps, T& scanline) {
0503     ps.clear();
0504     typename T::iterator itr = scanline.find(y);
0505     if(itr != scanline.begin()) {
0506       --itr;
0507       setProperty(ps, (*itr).second);
0508     }
0509   }
0510 
0511   template <typename T, typename T2>
0512   inline void writeGraph(T& graph, edge_property_vector& output, T2& scanline) {
0513     if(output.empty()) return;
0514     edge_property* previousEdgeP = &(output[0]);
0515     bool firstIteration = true;
0516     property_set ps;
0517     for(std::size_t i = 0; i < output.size(); ++i) {
0518       edge_property& previousEdge = *previousEdgeP;
0519       edge_property& edge = output[i];
0520       if(previousEdge.first.high() == edge.first.low()) {
0521         //horizontal edge
0522         insertEdges(graph, edge.second.first, previousEdge.second.first);
0523         //corner 1
0524         insertEdges(graph, edge.second.first, previousEdge.second.second);
0525         //other horizontal edge
0526         insertEdges(graph, edge.second.second, previousEdge.second.second);
0527         //corner 2
0528         insertEdges(graph, edge.second.second, previousEdge.second.first);
0529       } else {
0530         if(!firstIteration){
0531           //look up regions above previous edge
0532           propertySetAbove(previousEdge.first.high(), ps, scanline);
0533           insertEdges(graph, ps, previousEdge.second.first);
0534           insertEdges(graph, ps, previousEdge.second.second);
0535         }
0536         //look up regions below current edge in the scanline
0537         propertySetBelow(edge.first.high(), ps, scanline);
0538         insertEdges(graph, ps, edge.second.first);
0539         insertEdges(graph, ps, edge.second.second);
0540       }
0541       firstIteration = false;
0542       //vertical edge
0543       insertEdges(graph, edge.second.second, edge.second.first);
0544       //shared region to left
0545       insertEdges(graph, edge.second.second, edge.second.second);
0546       //shared region to right
0547       insertEdges(graph, edge.second.first, edge.second.first);
0548       previousEdgeP = &(output[i]);
0549     }
0550     edge_property& previousEdge = *previousEdgeP;
0551     propertySetAbove(previousEdge.first.high(), ps, scanline);
0552     insertEdges(graph, ps, previousEdge.second.first);
0553     insertEdges(graph, ps, previousEdge.second.second);
0554     output.clear();
0555   }
0556 
0557   template <typename Result>
0558   inline void writeOutput(coordinate_type x, Result& result, edge_property_vector& output) {
0559     for(std::size_t i = 0; i < output.size(); ++i) {
0560       edge_property& edge = output[i];
0561       //edge.second.first is the property set on the left of the edge
0562       if(!edge.second.first.empty()) {
0563         typename Result::iterator itr = result.find(edge.second.first);
0564         if(itr == result.end()) {
0565           std::pair<property_set, polygon_set_type> element(edge.second.first, polygon_set_type(VERTICAL));
0566           itr = result.insert(result.end(), element);
0567         }
0568         std::pair<interval_data<coordinate_type>, int> element2(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), -1); //right edge of figure
0569         (*itr).second.insert(x, element2);
0570       }
0571       if(!edge.second.second.empty()) {
0572         //edge.second.second is the property set on the right of the edge
0573         typename Result::iterator itr = result.find(edge.second.second);
0574         if(itr == result.end()) {
0575           std::pair<property_set, polygon_set_type> element(edge.second.second, polygon_set_type(VERTICAL));
0576           itr = result.insert(result.end(), element);
0577         }
0578         std::pair<interval_data<coordinate_type>, int> element3(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), 1); //left edge of figure
0579         (*itr).second.insert(x, element3);
0580       }
0581     }
0582     output.clear();
0583   }
0584 };
0585 
0586 }
0587 }
0588 #endif