Chris@16
|
1 /*
|
Chris@16
|
2 Copyright 2008 Intel Corporation
|
Chris@16
|
3
|
Chris@16
|
4 Use, modification and distribution are subject to the Boost Software License,
|
Chris@16
|
5 Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 http://www.boost.org/LICENSE_1_0.txt).
|
Chris@16
|
7 */
|
Chris@16
|
8 #ifndef BOOST_POLYGON_MAX_COVER_HPP
|
Chris@16
|
9 #define BOOST_POLYGON_MAX_COVER_HPP
|
Chris@16
|
10 namespace boost { namespace polygon{
|
Chris@16
|
11
|
Chris@16
|
12 template <typename Unit>
|
Chris@16
|
13 struct MaxCover {
|
Chris@16
|
14 typedef interval_data<Unit> Interval;
|
Chris@16
|
15 typedef rectangle_data<Unit> Rectangle;
|
Chris@16
|
16
|
Chris@16
|
17 class Node {
|
Chris@16
|
18 private:
|
Chris@16
|
19 std::vector<Node*> children_;
|
Chris@16
|
20 std::set<Interval> tracedPaths_;
|
Chris@16
|
21 public:
|
Chris@16
|
22 Rectangle rect;
|
Chris@16
|
23 Node() : children_(), tracedPaths_(), rect() {}
|
Chris@16
|
24 Node(const Rectangle rectIn) : children_(), tracedPaths_(), rect(rectIn) {}
|
Chris@16
|
25 typedef typename std::vector<Node*>::iterator iterator;
|
Chris@16
|
26 inline iterator begin() { return children_.begin(); }
|
Chris@16
|
27 inline iterator end() { return children_.end(); }
|
Chris@16
|
28 inline void add(Node* child) { children_.push_back(child); }
|
Chris@16
|
29 inline bool tracedPath(const Interval& ivl) const {
|
Chris@16
|
30 return tracedPaths_.find(ivl) != tracedPaths_.end();
|
Chris@16
|
31 }
|
Chris@16
|
32 inline void addPath(const Interval& ivl) {
|
Chris@16
|
33 tracedPaths_.insert(tracedPaths_.end(), ivl);
|
Chris@16
|
34 }
|
Chris@16
|
35 };
|
Chris@16
|
36
|
Chris@16
|
37 typedef std::pair<std::pair<Unit, Interval>, Node* > EdgeAssociation;
|
Chris@16
|
38
|
Chris@16
|
39 class lessEdgeAssociation : public std::binary_function<const EdgeAssociation&, const EdgeAssociation&, bool> {
|
Chris@16
|
40 public:
|
Chris@16
|
41 inline lessEdgeAssociation() {}
|
Chris@16
|
42 inline bool operator () (const EdgeAssociation& elem1, const EdgeAssociation& elem2) const {
|
Chris@16
|
43 if(elem1.first.first < elem2.first.first) return true;
|
Chris@16
|
44 if(elem1.first.first > elem2.first.first) return false;
|
Chris@16
|
45 return elem1.first.second < elem2.first.second;
|
Chris@16
|
46 }
|
Chris@16
|
47 };
|
Chris@16
|
48
|
Chris@16
|
49 template <class cT>
|
Chris@16
|
50 static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient) {
|
Chris@16
|
51 Interval rectIvl = node->rect.get(orient);
|
Chris@16
|
52 if(node->tracedPath(rectIvl)) {
|
Chris@16
|
53 return;
|
Chris@16
|
54 }
|
Chris@16
|
55 node->addPath(rectIvl);
|
Chris@16
|
56 if(node->begin() == node->end()) {
|
Chris@16
|
57 //std::cout << "WRITE OUT 3: " << node->rect << std::endl;
|
Chris@16
|
58 outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(node->rect));
|
Chris@16
|
59 return;
|
Chris@16
|
60 }
|
Chris@16
|
61 bool writeOut = true;
|
Chris@16
|
62 for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) {
|
Chris@16
|
63 getMaxCover(outputContainer, *itr, orient, node->rect); //get rectangles down path
|
Chris@16
|
64 Interval nodeIvl = (*itr)->rect.get(orient);
|
Chris@16
|
65 if(contains(nodeIvl, rectIvl, true)) writeOut = false;
|
Chris@16
|
66 }
|
Chris@16
|
67 if(writeOut) {
|
Chris@16
|
68 //std::cout << "WRITE OUT 2: " << node->rect << std::endl;
|
Chris@16
|
69 outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(node->rect));
|
Chris@16
|
70 }
|
Chris@16
|
71 }
|
Chris@16
|
72
|
Chris@16
|
73 struct stack_element {
|
Chris@16
|
74 inline stack_element() :
|
Chris@16
|
75 node(), rect(), itr() {}
|
Chris@16
|
76 inline stack_element(Node* n,
|
Chris@16
|
77 const Rectangle& r,
|
Chris@16
|
78 typename Node::iterator i) :
|
Chris@16
|
79 node(n), rect(r), itr(i) {}
|
Chris@16
|
80 Node* node;
|
Chris@16
|
81 Rectangle rect;
|
Chris@16
|
82 typename Node::iterator itr;
|
Chris@16
|
83 };
|
Chris@16
|
84
|
Chris@16
|
85 template <class cT>
|
Chris@16
|
86 static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient,
|
Chris@16
|
87 Rectangle rect) {
|
Chris@16
|
88 //std::cout << "New Root\n";
|
Chris@16
|
89 std::vector<stack_element> stack;
|
Chris@16
|
90 typename Node::iterator itr = node->begin();
|
Chris@16
|
91 do {
|
Chris@16
|
92 //std::cout << "LOOP\n";
|
Chris@16
|
93 //std::cout << node->rect << std::endl;
|
Chris@16
|
94 Interval rectIvl = rect.get(orient);
|
Chris@16
|
95 Interval nodeIvl = node->rect.get(orient);
|
Chris@16
|
96 bool iresult = intersect(rectIvl, nodeIvl, false);
|
Chris@16
|
97 bool tresult = !node->tracedPath(rectIvl);
|
Chris@16
|
98 //std::cout << (itr != node->end()) << " " << iresult << " " << tresult << std::endl;
|
Chris@16
|
99 Rectangle nextRect1 = Rectangle(rectIvl, rectIvl);
|
Chris@16
|
100 Unit low = rect.get(orient.get_perpendicular()).low();
|
Chris@16
|
101 Unit high = node->rect.get(orient.get_perpendicular()).high();
|
Chris@16
|
102 nextRect1.set(orient.get_perpendicular(), Interval(low, high));
|
Chris@16
|
103 if(iresult && tresult) {
|
Chris@16
|
104 node->addPath(rectIvl);
|
Chris@16
|
105 bool writeOut = true;
|
Chris@16
|
106 //check further visibility beyond this node
|
Chris@16
|
107 for(typename Node::iterator itr2 = node->begin(); itr2 != node->end(); ++itr2) {
|
Chris@16
|
108 Interval nodeIvl3 = (*itr2)->rect.get(orient);
|
Chris@16
|
109 //if a child of this node can contain the interval then we can extend through
|
Chris@16
|
110 if(contains(nodeIvl3, rectIvl, true)) writeOut = false;
|
Chris@16
|
111 //std::cout << "child " << (*itr2)->rect << std::endl;
|
Chris@16
|
112 }
|
Chris@16
|
113 Rectangle nextRect2 = Rectangle(rectIvl, rectIvl);
|
Chris@16
|
114 Unit low2 = rect.get(orient.get_perpendicular()).low();
|
Chris@16
|
115 Unit high2 = node->rect.get(orient.get_perpendicular()).high();
|
Chris@16
|
116 nextRect2.set(orient.get_perpendicular(), Interval(low2, high2));
|
Chris@16
|
117 if(writeOut) {
|
Chris@16
|
118 //std::cout << "write out " << nextRect << std::endl;
|
Chris@16
|
119 outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect2));
|
Chris@16
|
120 } else {
|
Chris@101
|
121 //std::cout << "suppress " << nextRect << std::endl;
|
Chris@16
|
122 }
|
Chris@16
|
123 }
|
Chris@16
|
124 if(itr != node->end() && iresult && tresult) {
|
Chris@16
|
125 //std::cout << "recurse into child\n";
|
Chris@16
|
126 stack.push_back(stack_element(node, rect, itr));
|
Chris@16
|
127 rect = nextRect1;
|
Chris@16
|
128 node = *itr;
|
Chris@16
|
129 itr = node->begin();
|
Chris@16
|
130 } else {
|
Chris@16
|
131 if(!stack.empty()) {
|
Chris@16
|
132 //std::cout << "recurse out of child\n";
|
Chris@16
|
133 node = stack.back().node;
|
Chris@16
|
134 rect = stack.back().rect;
|
Chris@16
|
135 itr = stack.back().itr;
|
Chris@16
|
136 stack.pop_back();
|
Chris@16
|
137 } else {
|
Chris@16
|
138 //std::cout << "empty stack\n";
|
Chris@16
|
139 //if there were no children of the root node
|
Chris@16
|
140 // Rectangle nextRect = Rectangle(rectIvl, rectIvl);
|
Chris@16
|
141 // Unit low = rect.get(orient.get_perpendicular()).low();
|
Chris@16
|
142 // Unit high = node->rect.get(orient.get_perpendicular()).high();
|
Chris@16
|
143 // nextRect.set(orient.get_perpendicular(), Interval(low, high));
|
Chris@16
|
144 // outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect));
|
Chris@16
|
145 }
|
Chris@16
|
146 //std::cout << "increment " << (itr != node->end()) << std::endl;
|
Chris@16
|
147 if(itr != node->end()) {
|
Chris@16
|
148 ++itr;
|
Chris@16
|
149 if(itr != node->end()) {
|
Chris@16
|
150 //std::cout << "recurse into next child.\n";
|
Chris@16
|
151 stack.push_back(stack_element(node, rect, itr));
|
Chris@16
|
152 Interval rectIvl2 = rect.get(orient);
|
Chris@16
|
153 Interval nodeIvl2 = node->rect.get(orient);
|
Chris@16
|
154 /*bool iresult =*/ intersect(rectIvl2, nodeIvl2, false);
|
Chris@16
|
155 Rectangle nextRect2 = Rectangle(rectIvl2, rectIvl2);
|
Chris@16
|
156 Unit low2 = rect.get(orient.get_perpendicular()).low();
|
Chris@16
|
157 Unit high2 = node->rect.get(orient.get_perpendicular()).high();
|
Chris@16
|
158 nextRect2.set(orient.get_perpendicular(), Interval(low2, high2));
|
Chris@16
|
159 rect = nextRect2;
|
Chris@16
|
160 //std::cout << "rect for next child" << rect << std::endl;
|
Chris@16
|
161 node = *itr;
|
Chris@16
|
162 itr = node->begin();
|
Chris@16
|
163 }
|
Chris@16
|
164 }
|
Chris@16
|
165 }
|
Chris@16
|
166 } while(!stack.empty() || itr != node->end());
|
Chris@16
|
167 }
|
Chris@16
|
168
|
Chris@16
|
169 /* Function recursive version of getMaxCover
|
Chris@16
|
170 Because the code is so much simpler than the loop algorithm I retain it for clarity
|
Chris@16
|
171
|
Chris@16
|
172 template <class cT>
|
Chris@16
|
173 static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient,
|
Chris@16
|
174 const Rectangle& rect) {
|
Chris@16
|
175 Interval rectIvl = rect.get(orient);
|
Chris@16
|
176 Interval nodeIvl = node->rect.get(orient);
|
Chris@16
|
177 if(!intersect(rectIvl, nodeIvl, false)) {
|
Chris@16
|
178 return;
|
Chris@16
|
179 }
|
Chris@16
|
180 if(node->tracedPath(rectIvl)) {
|
Chris@16
|
181 return;
|
Chris@16
|
182 }
|
Chris@16
|
183 node->addPath(rectIvl);
|
Chris@16
|
184 Rectangle nextRect(rectIvl, rectIvl);
|
Chris@16
|
185 Unit low = rect.get(orient.get_perpendicular()).low();
|
Chris@16
|
186 Unit high = node->rect.get(orient.get_perpendicular()).high();
|
Chris@16
|
187 nextRect.set(orient.get_perpendicular(), Interval(low, high));
|
Chris@16
|
188 bool writeOut = true;
|
Chris@16
|
189 rectIvl = nextRect.get(orient);
|
Chris@16
|
190 for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) {
|
Chris@16
|
191 nodeIvl = (*itr)->rect.get(orient);
|
Chris@16
|
192 if(contains(nodeIvl, rectIvl, true)) writeOut = false;
|
Chris@16
|
193 }
|
Chris@16
|
194 if(writeOut) {
|
Chris@16
|
195 outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect));
|
Chris@16
|
196 }
|
Chris@16
|
197 for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) {
|
Chris@16
|
198 getMaxCover(outputContainer, *itr, orient, nextRect);
|
Chris@16
|
199 }
|
Chris@16
|
200 }
|
Chris@16
|
201 */
|
Chris@16
|
202
|
Chris@16
|
203 //iterator range is assummed to be in topological order meaning all node's trailing
|
Chris@16
|
204 //edges are in sorted order
|
Chris@16
|
205 template <class iT>
|
Chris@16
|
206 static inline void computeDag(iT beginNode, iT endNode, orientation_2d orient,
|
Chris@16
|
207 std::size_t size) {
|
Chris@16
|
208 std::vector<EdgeAssociation> leadingEdges;
|
Chris@16
|
209 leadingEdges.reserve(size);
|
Chris@16
|
210 for(iT iter = beginNode; iter != endNode; ++iter) {
|
Chris@16
|
211 Node* nodep = &(*iter);
|
Chris@16
|
212 Unit leading = nodep->rect.get(orient.get_perpendicular()).low();
|
Chris@16
|
213 Interval rectIvl = nodep->rect.get(orient);
|
Chris@16
|
214 leadingEdges.push_back(EdgeAssociation(std::pair<Unit, Interval>(leading, rectIvl), nodep));
|
Chris@16
|
215 }
|
Chris@16
|
216 polygon_sort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation());
|
Chris@16
|
217 typename std::vector<EdgeAssociation>::iterator leadingBegin = leadingEdges.begin();
|
Chris@16
|
218 iT trailingBegin = beginNode;
|
Chris@16
|
219 while(leadingBegin != leadingEdges.end()) {
|
Chris@16
|
220 EdgeAssociation& leadingSegment = (*leadingBegin);
|
Chris@16
|
221 Unit trailing = (*trailingBegin).rect.get(orient.get_perpendicular()).high();
|
Chris@16
|
222 Interval ivl = (*trailingBegin).rect.get(orient);
|
Chris@16
|
223 std::pair<Unit, Interval> trailingSegment(trailing, ivl);
|
Chris@16
|
224 if(leadingSegment.first.first < trailingSegment.first) {
|
Chris@16
|
225 ++leadingBegin;
|
Chris@16
|
226 continue;
|
Chris@16
|
227 }
|
Chris@16
|
228 if(leadingSegment.first.first > trailingSegment.first) {
|
Chris@16
|
229 ++trailingBegin;
|
Chris@16
|
230 continue;
|
Chris@16
|
231 }
|
Chris@16
|
232 if(leadingSegment.first.second.high() <= trailingSegment.second.low()) {
|
Chris@16
|
233 ++leadingBegin;
|
Chris@16
|
234 continue;
|
Chris@16
|
235 }
|
Chris@16
|
236 if(trailingSegment.second.high() <= leadingSegment.first.second.low()) {
|
Chris@16
|
237 ++trailingBegin;
|
Chris@16
|
238 continue;
|
Chris@16
|
239 }
|
Chris@16
|
240 //leading segment intersects trailing segment
|
Chris@16
|
241 (*trailingBegin).add((*leadingBegin).second);
|
Chris@16
|
242 if(leadingSegment.first.second.high() > trailingSegment.second.high()) {
|
Chris@16
|
243 ++trailingBegin;
|
Chris@16
|
244 continue;
|
Chris@16
|
245 }
|
Chris@16
|
246 if(trailingSegment.second.high() > leadingSegment.first.second.high()) {
|
Chris@16
|
247 ++leadingBegin;
|
Chris@16
|
248 continue;
|
Chris@16
|
249 }
|
Chris@16
|
250 ++leadingBegin;
|
Chris@16
|
251 ++trailingBegin;
|
Chris@16
|
252 }
|
Chris@16
|
253 }
|
Chris@16
|
254
|
Chris@16
|
255 template <class cT>
|
Chris@16
|
256 static inline void getMaxCover(cT& outputContainer,
|
Chris@16
|
257 const std::vector<Rectangle>& rects, orientation_2d orient) {
|
Chris@16
|
258 if(rects.empty()) return;
|
Chris@16
|
259 std::vector<Node> nodes;
|
Chris@16
|
260 {
|
Chris@16
|
261 if(rects.size() == 1) {
|
Chris@16
|
262 outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(rects[0]));
|
Chris@16
|
263 return;
|
Chris@16
|
264 }
|
Chris@16
|
265 nodes.reserve(rects.size());
|
Chris@16
|
266 for(std::size_t i = 0; i < rects.size(); ++i) { nodes.push_back(Node(rects[i])); }
|
Chris@16
|
267 }
|
Chris@16
|
268 computeDag(nodes.begin(), nodes.end(), orient, nodes.size());
|
Chris@16
|
269 for(std::size_t i = 0; i < nodes.size(); ++i) {
|
Chris@16
|
270 getMaxCover(outputContainer, &(nodes[i]), orient);
|
Chris@16
|
271 }
|
Chris@16
|
272 }
|
Chris@16
|
273
|
Chris@16
|
274 };
|
Chris@16
|
275 }
|
Chris@16
|
276 }
|
Chris@16
|
277
|
Chris@16
|
278 #endif
|