Left: | ||
Right: |
OLD | NEW |
---|---|
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 2006--2012 Joe Neeman <joeneeman@gmail.com> | 4 Copyright (C) 2006--2012 Joe Neeman <joeneeman@gmail.com> |
5 | 5 |
6 LilyPond is free software: you can redistribute it and/or modify | 6 LilyPond is free software: you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
8 the Free Software Foundation, either version 3 of the License, or | 8 the Free Software Foundation, either version 3 of the License, or |
9 (at your option) any later version. | 9 (at your option) any later version. |
10 | 10 |
11 LilyPond is distributed in the hope that it will be useful, | 11 LilyPond is distributed in the hope that it will be useful, |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 GNU General Public License for more details. | 14 GNU General Public License for more details. |
15 | 15 |
16 You should have received a copy of the GNU General Public License | 16 You should have received a copy of the GNU General Public License |
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>. | 17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>. |
18 */ | 18 */ |
19 | 19 |
20 #include "skyline.hh" | 20 #include "skyline.hh" |
21 #include "skyline-pair.hh" | |
21 #include <deque> | 22 #include <deque> |
22 #include <cstdio> | 23 #include <cstdio> |
23 | 24 |
24 #include "ly-smobs.icc" | 25 #include "ly-smobs.icc" |
25 | 26 |
26 /* A skyline is a sequence of non-overlapping buildings: something like | 27 /* A skyline is a sequence of non-overlapping buildings: something like |
27 this: | 28 this: |
28 _______ | 29 _______ |
29 | \ ________ | 30 | \ ________ |
30 | \ ________/ \ | 31 | \ ________/ \ |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 for (vsize i = 0; i < ps.size (); i++) | 81 for (vsize i = 0; i < ps.size (); i++) |
81 printf ("(%f,%f)%s", ps[i][X_AXIS], ps[i][Y_AXIS], | 82 printf ("(%f,%f)%s", ps[i][X_AXIS], ps[i][Y_AXIS], |
82 (i % 2) == 1 ? "\n" : " "); | 83 (i % 2) == 1 ? "\n" : " "); |
83 } | 84 } |
84 | 85 |
85 Building::Building (Real start, Real start_height, Real end_height, Real end) | 86 Building::Building (Real start, Real start_height, Real end_height, Real end) |
86 { | 87 { |
87 if (isinf (start) || isinf (end)) | 88 if (isinf (start) || isinf (end)) |
88 assert (start_height == end_height); | 89 assert (start_height == end_height); |
89 | 90 |
91 start_ = start; | |
90 end_ = end; | 92 end_ = end; |
91 precompute (start, start_height, end_height, end); | 93 precompute (start, start_height, end_height, end); |
92 } | 94 } |
93 | 95 |
94 Building::Building (Box const &b, Real horizon_padding, Axis horizon_axis, Direc tion sky) | 96 Building::Building (Box const &b, Axis horizon_axis, Direction sky) |
95 { | 97 { |
96 Real start = b[horizon_axis][LEFT] - horizon_padding; | 98 Real start = b[horizon_axis][LEFT]; |
97 Real end = b[horizon_axis][RIGHT] + horizon_padding; | 99 Real end = b[horizon_axis][RIGHT]; |
98 Real height = sky * b[other_axis (horizon_axis)][sky]; | 100 Real height = sky * b[other_axis (horizon_axis)][sky]; |
99 | 101 |
102 start_ = start; | |
100 end_ = end; | 103 end_ = end; |
101 precompute (start, height, height, end); | 104 precompute (start, height, height, end); |
102 } | 105 } |
103 | 106 |
104 void | 107 void |
105 Building::precompute (Real start, Real start_height, Real end_height, Real end) | 108 Building::precompute (Real start, Real start_height, Real end_height, Real end) |
106 { | 109 { |
107 slope_ = (end_height - start_height) / (end - start); | 110 slope_ = 0.0; /* if they were both infinite, we would get nan, not 0, from the prev line */ |
108 if (start_height == end_height) /* if they were both infinite, we would get na n, not 0, from the prev line */ | 111 if (start_height != end_height) |
109 slope_ = 0; | 112 slope_ = (end_height - start_height) / (end - start); |
110 | 113 |
111 assert (!isinf (slope_) && !isnan (slope_)); | 114 assert (!isinf (slope_) && !isnan (slope_)); |
112 | 115 |
113 if (isinf (start)) | 116 if (isinf (start)) |
114 { | 117 { |
115 assert (start_height == end_height); | 118 assert (start_height == end_height); |
116 y_intercept_ = start_height; | 119 y_intercept_ = start_height; |
117 } | 120 } |
118 else | 121 else |
119 y_intercept_ = start_height - slope_ * start; | 122 y_intercept_ = start_height - slope_ * start; |
120 } | 123 } |
121 | 124 |
122 Real | 125 inline Real |
123 Building::height (Real x) const | 126 Building::height (Real x) const |
124 { | 127 { |
125 return isinf (x) ? y_intercept_ : slope_ * x + y_intercept_; | 128 return isinf (x) ? y_intercept_ : slope_ * x + y_intercept_; |
126 } | 129 } |
127 | 130 |
128 void | 131 void |
129 Building::print () const | 132 Building::print () const |
130 { | 133 { |
131 printf ("%f x + %f ends at %f\n", slope_, y_intercept_, end_); | 134 printf ("%f x + %f from %f to %f\n", slope_, y_intercept_, start_, end_); |
132 } | 135 } |
133 | 136 |
134 Real | 137 inline Real |
135 Building::intersection_x (Building const &other) const | 138 Building::intersection_x (Building const &other) const |
136 { | 139 { |
137 Real ret = (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_); | 140 Real ret = (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_); |
138 return isnan (ret) ? -infinity_f : ret; | 141 return isnan (ret) ? -infinity_f : ret; |
139 } | 142 } |
140 | 143 |
141 void | 144 void |
142 Building::leading_part (Real chop) | 145 Building::leading_part (Real chop) |
143 { | 146 { |
144 assert (chop <= end_); | 147 assert (chop <= end_); |
145 end_ = chop; | 148 end_ = chop; |
146 } | 149 } |
147 | 150 |
148 Building | 151 // Returns a shift s such that (x + s, y) intersects the roof of |
149 Building::sloped_neighbour (Real start, Real horizon_padding, Direction d) const | 152 // this building. If no such shift exists, returns infinity_f. |
153 Real | |
154 Building::shift_to_intersect (Real x, Real y) const | |
150 { | 155 { |
151 Real x = (d == LEFT) ? start : end_; | 156 // Solve for s: y = (x + s)*m + b |
152 Real left = x; | 157 Real ret = (y - y_intercept_ - slope_ * x) / slope_; |
153 Real right = x + d * horizon_padding; | 158 |
154 Real left_height = height (x); | 159 if (ret >= start_ && ret <= end_ && !isinf (ret)) |
155 Real right_height = left_height - horizon_padding; | 160 return ret; |
156 if (d == LEFT) | 161 return infinity_f; |
157 { | 162 } |
158 swap (left, right); | 163 |
159 swap (left_height, right_height); | 164 // Returns the interval of horizontal shifts for which this |
160 } | 165 // building (pointing up) overlaps the other building (pointing down). |
161 return Building (left, left_height, right_height, right); | 166 Interval |
167 Building::overlapping_shift_interval (Building const& other) const | |
168 { | |
169 Interval iv; | |
170 | |
171 // If one building is empty, there will never be an overlap. | |
172 if (y_intercept_ == -infinity_f || other.y_intercept_ == -infinity_f) | |
173 return iv; | |
174 | |
175 // There are two kinds of interesting positions: | |
176 // - when the horizontal extents of the buildings just touch | |
177 // - when an endpoint of one building intersects the roof of the other. | |
178 // The interval we are looking for is the smallest one that | |
179 // contains all of the interesting points. | |
180 | |
181 | |
182 Real my_y1 = height (start_); | |
183 Real my_y2 = height (end_); | |
184 Real his_y1 = -other.height (other.start_); // "-" because OTHER points down | |
185 Real his_y2 = -other.height (other.end_); | |
186 | |
187 // If both buildings are infinite in the same direction, | |
188 // the return value is either empty or full. | |
189 if ((isinf (start_) && isinf (other.start_)) | |
190 || (isinf (end_) && isinf (other.end_))) | |
191 return (y_intercept_ > other.y_intercept_) | |
192 ? Interval (-infinity_f, infinity_f) : Interval (); | |
193 | |
194 // ...when the horizontal extents of the buildings just touch... | |
195 if (my_y1 >= his_y2) | |
196 iv.add_point (other.end_ - start_); | |
197 if (my_y2 >= his_y1) | |
198 iv.add_point (other.start_ - end_); | |
199 | |
200 // ...when an endpoint of one building intersects the roof of the other. | |
201 Real p1 = shift_to_intersect (other.start_, his_y1); | |
202 Real p2 = shift_to_intersect (other.end_, his_y2); | |
203 // "-my_y1" because OTHER points down: | |
204 Real p3 = other.shift_to_intersect (start_, -my_y1); | |
205 Real p4 = other.shift_to_intersect (end_, -my_y2); | |
206 if (!isinf (p1)) | |
207 iv.add_point (p1); | |
208 if (!isinf (p2)) | |
209 iv.add_point (p2); | |
210 if (!isinf (p3)) | |
211 iv.add_point (p3); | |
212 if (!isinf (p4)) | |
213 iv.add_point (p4); | |
214 | |
215 return iv; | |
162 } | 216 } |
163 | 217 |
164 static Real | 218 static Real |
165 first_intersection (Building const &b, list<Building> *const s, Real start_x) | 219 first_intersection (Building const &b, list<Building> *const s, Real start_x) |
166 { | 220 { |
167 while (!s->empty () && start_x < b.end_) | 221 while (!s->empty () && start_x < b.end_) |
168 { | 222 { |
169 Building c = s->front (); | 223 Building c = s->front (); |
224 | |
225 // conceals and intersection_x involve multiplication and | |
226 // division. Avoid that, if we can. | |
227 if (c.y_intercept_ == -infinity_f) | |
228 { | |
229 if (c.end_ > b.end_) | |
230 return b.end_; | |
231 start_x = c.end_; | |
232 s->pop_front (); | |
233 continue; | |
234 } | |
235 | |
170 if (c.conceals (b, start_x)) | 236 if (c.conceals (b, start_x)) |
171 return start_x; | 237 return start_x; |
172 | 238 |
173 Real i = b.intersection_x (c); | 239 Real i = b.intersection_x (c); |
174 if (i > start_x && i <= b.end_ && i <= c.end_) | 240 if (i > start_x && i <= b.end_ && i <= c.end_) |
175 return i; | 241 return i; |
176 | 242 |
177 start_x = c.end_; | 243 start_x = c.end_; |
178 if (b.end_ > c.end_) | 244 if (b.end_ > c.end_) |
179 s->pop_front (); | 245 s->pop_front (); |
180 } | 246 } |
181 return b.end_; | 247 return b.end_; |
182 } | 248 } |
183 | 249 |
184 bool | 250 bool |
185 Building::conceals (Building const &other, Real x) const | 251 Building::conceals (Building const &other, Real x) const |
186 { | 252 { |
187 if (slope_ == other.slope_) | 253 if (slope_ == other.slope_) |
188 return y_intercept_ > other.y_intercept_; | 254 return y_intercept_ > other.y_intercept_; |
189 | 255 |
190 /* their slopes were not equal, so there is an intersection point */ | 256 /* their slopes were not equal, so there is an intersection point */ |
191 Real i = intersection_x (other); | 257 Real i = intersection_x (other); |
192 return (i <= x && slope_ > other.slope_) | 258 return (i <= x && slope_ > other.slope_) |
193 || (i > x && slope_ < other.slope_); | 259 || (i > x && slope_ < other.slope_); |
194 } | 260 } |
195 | 261 |
196 void | 262 void |
263 Skyline::deholify () | |
264 { | |
265 bool has_anchor = false; | |
266 for (list<Building>::iterator i (buildings_.begin ()); | |
267 i != buildings_.end (); i++) | |
268 if (!isinf (i->y_intercept_)) | |
269 { | |
270 has_anchor = true; | |
271 break; | |
272 } | |
273 | |
274 if (!has_anchor) | |
275 return; | |
276 | |
277 bool dirty = false; | |
278 | |
279 do | |
280 { | |
281 bool dirty = false;·· | |
dak
2012/07/09 08:42:16
Trailing whitespace at end of line, but actually t
| |
282 bool do_correction = false; | |
283 list<Building>::iterator center; | |
284 list<Building>::iterator left; | |
285 | |
286 for (list<Building>::iterator i (buildings_.begin ()); | |
287 i != buildings_.end (); i++) | |
288 { | |
289 if (do_correction) | |
290 { | |
291 dirty = true; | |
292 Real p1 = left->end_ * left->slope_ + left->y_intercept_; | |
293 Real p2 = i->start_ * i->slope_ + i->y_intercept_; | |
294 center->slope_ = (p2 - p1) / (center->end_ - center->start_); | |
295 center->y_intercept_ = p2 - (center->end_ * center->slope_); | |
296 } | |
297 do_correction = isinf (i->y_intercept_) && !(i == buildings_.begin ()) ; | |
298 left = center; | |
299 center = i; | |
300 } | |
301 } | |
302 while (dirty); | |
303 } | |
304 | |
305 void | |
197 Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2, | 306 Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2, |
198 list<Building> *const result) | 307 list<Building> *const result) const |
199 { | 308 { |
200 if (s1->empty () || s2->empty ()) | 309 if (s1->empty () || s2->empty ()) |
201 { | 310 { |
202 programming_error ("tried to merge an empty skyline"); | 311 programming_error ("tried to merge an empty skyline"); |
203 return; | 312 return; |
204 } | 313 } |
205 | 314 |
206 Real x = -infinity_f; | 315 Real x = -infinity_f; |
207 while (!s1->empty ()) | 316 while (!s1->empty ()) |
208 { | 317 { |
209 if (s2->front ().conceals (s1->front (), x)) | 318 if (s2->front ().conceals (s1->front (), x)) |
210 swap (s1, s2); | 319 swap (s1, s2); |
211 | 320 |
212 Building b = s1->front (); | 321 Building b = s1->front (); |
322 Building c = s2->front (); | |
323 | |
324 // Optimization: if the other skyline is empty at this point, | |
325 // we can avoid testing some intersections. Just grab as many | |
326 // buildings from s1 as we can, and shove them onto the output. | |
327 if (c.y_intercept_ == -infinity_f | |
328 && c.end_ >= b.end_) | |
329 { | |
330 list<Building>::iterator i = s1->begin (); | |
331 i++; | |
332 while (i != s1->end () && i->end_ <= c.end_) | |
333 i++; | |
334 | |
335 s1->front ().start_ = x; | |
336 result->splice (result->end (), *s1, s1->begin (), i); | |
337 x = result->back ().end_; | |
338 continue; | |
339 } | |
340 | |
213 Real end = first_intersection (b, s2, x); | 341 Real end = first_intersection (b, s2, x); |
214 | |
215 if (s2->empty ()) | 342 if (s2->empty ()) |
216 { | 343 { |
217 result->push_front (b); | 344 b.start_ = result->back ().end_; |
345 result->push_back (b); | |
218 break; | 346 break; |
219 } | 347 } |
220 | 348 |
221 /* only include buildings wider than epsilon */ | 349 /* only include buildings wider than epsilon */ |
222 if (end > x + EPS) | 350 if (end > x + EPS) |
223 { | 351 { |
224 b.leading_part (end); | 352 b.leading_part (end); |
225 result->push_front (b); | 353 b.start_ = result->back ().end_; |
354 result->push_back (b); | |
226 } | 355 } |
227 | 356 |
228 if (end >= s1->front ().end_) | 357 if (end >= s1->front ().end_) |
229 s1->pop_front (); | 358 s1->pop_front (); |
230 | 359 |
231 x = end; | 360 x = end; |
232 } | 361 } |
233 result->reverse (); | |
234 } | 362 } |
235 | 363 |
236 static void | 364 static void |
237 empty_skyline (list<Building> *const ret) | 365 empty_skyline (list<Building> *const ret) |
238 { | 366 { |
239 ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f)) ; | 367 ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f)) ; |
240 } | 368 } |
241 | 369 |
242 /* | 370 /* |
243 Given Building 'b' with starting wall location 'start', extend each side | 371 Given Building 'b', build a skyline containing only that building. |
244 with a sloped roofline of width 'horizon_padding'; put the skyline in 'ret' | |
245 */ | 372 */ |
246 static void | 373 static void |
247 single_skyline (Building b, Real start, Real horizon_padding, list<Building> *co nst ret) | 374 single_skyline (Building b, list<Building> *const ret) |
248 { | 375 { |
249 bool sloped_neighbours = horizon_padding > 0 && !isinf (start) && !isinf (b.en d_); | 376 if (b.end_ > b.start_ + EPS) |
250 if (!isinf (b.end_)) | 377 { |
251 ret->push_front (Building (b.end_ + horizon_padding, -infinity_f, | 378 ret->push_back (Building (-infinity_f, -infinity_f, |
252 -infinity_f, infinity_f)); | 379 -infinity_f, b.start_)); |
253 if (sloped_neighbours) | 380 ret->push_back (b); |
254 ret->push_front (b.sloped_neighbour (start, horizon_padding, RIGHT)); | 381 ret->push_back (Building (b.end_, -infinity_f, |
255 | 382 -infinity_f, infinity_f)); |
256 if (b.end_ > start + EPS) | 383 } |
257 ret->push_front (b); | 384 else |
258 | 385 { |
259 if (sloped_neighbours) | 386 empty_skyline (ret); |
260 ret->push_front (b.sloped_neighbour (start, horizon_padding, LEFT)); | 387 } |
261 | |
262 if (!isinf (start)) | |
263 ret->push_front (Building (-infinity_f, -infinity_f, | |
264 -infinity_f, start - horizon_padding)); | |
265 } | 388 } |
266 | 389 |
267 /* remove a non-overlapping set of boxes from BOXES and build a skyline | 390 /* remove a non-overlapping set of boxes from BOXES and build a skyline |
268 out of them */ | 391 out of them */ |
269 static list<Building> | 392 static list<Building> |
270 non_overlapping_skyline (list<Box> *const boxes, Real horizon_padding, Axis hori zon_axis, Direction sky) | 393 non_overlapping_skyline (list<Building> *const buildings) |
271 { | 394 { |
272 list<Building> result; | 395 list<Building> result; |
273 Real last_end = -infinity_f; | 396 Real last_end = -infinity_f; |
274 list<Box>::iterator i = boxes->begin (); | 397 Building last_building (-infinity_f, -infinity_f, -infinity_f, infinity_f); |
275 while (i != boxes->end ()) | 398 list<Building>::iterator i = buildings->begin (); |
399 while (i != buildings->end ()) | |
276 { | 400 { |
277 Interval iv = (*i)[horizon_axis]; | 401 Real x1 = i->start_; |
402 Real y1 = i->height (i->start_); | |
403 Real x2 = i->end_; | |
404 Real y2 = i->height (i->end_); | |
278 | 405 |
279 if (iv[LEFT] - horizon_padding < last_end) | 406 // Drop buildings that will obviously have no effect. |
407 if (last_building.height (x1) >= y1 | |
408 && last_building.end_ >= x2 | |
409 && last_building.height (x2) >= y2) | |
410 { | |
411 list<Building>::iterator j = i++; | |
412 buildings->erase (j); | |
413 continue; | |
414 } | |
415 | |
416 if (x1 < last_end) | |
280 { | 417 { |
281 i++; | 418 i++; |
282 continue; | 419 continue; |
283 } | 420 } |
284 | 421 |
285 if (iv[LEFT] - horizon_padding > last_end + EPS) | 422 if (x1 > last_end + EPS) |
286 result.push_front (Building (last_end, -infinity_f, -infinity_f, iv[LEFT ] - 2 * horizon_padding)); | 423 result.push_back (Building (last_end, -infinity_f, -infinity_f, x1)); |
287 | 424 |
288 Building b (*i, horizon_padding, horizon_axis, sky); | 425 result.push_back (*i); |
289 bool sloped_neighbours = horizon_padding > 0 && !isinf (iv.length ()); | 426 last_building = *i; |
290 if (sloped_neighbours) | 427 last_end = i->end_; |
291 result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horiz on_padding, LEFT)); | |
292 result.push_front (b); | |
293 if (sloped_neighbours) | |
294 result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horiz on_padding, RIGHT)); | |
295 | 428 |
296 list<Box>::iterator j = i++; | 429 list<Building>::iterator j = i++; |
297 boxes->erase (j); | 430 buildings->erase (j); |
298 last_end = result.front ().end_; | |
299 } | 431 } |
432 | |
300 if (last_end < infinity_f) | 433 if (last_end < infinity_f) |
301 result.push_front (Building (last_end, -infinity_f, -infinity_f, infinity_f) ); | 434 result.push_back (Building (last_end, -infinity_f, -infinity_f, infinity_f)) ; |
302 result.reverse (); | |
303 return result; | 435 return result; |
304 } | 436 } |
305 | 437 |
306 class LessThanBox | 438 class LessThanBuilding |
307 { | 439 { |
308 Axis a_; | |
309 | |
310 public: | 440 public: |
311 LessThanBox (Axis a) | 441 bool operator () (Building const &b1, Building const &b2) |
312 { | 442 { |
313 a_ = a; | 443 return b1.start_ < b2.start_ |
314 } | 444 || (b1.start_ == b2.start_ && b1.height (b1.start_) > b2.height (b1.start_ )); |
315 | |
316 bool operator () (Box const &b1, Box const &b2) | |
317 { | |
318 return b1[a_][LEFT] < b2[a_][LEFT]; | |
319 } | 445 } |
320 }; | 446 }; |
321 | 447 |
448 /** | |
449 BUILDINGS is a list of buildings, but they could be overlapping | |
450 and in any order. The returned list of buildings is ordered and non-overlapp ing. | |
451 */ | |
322 list<Building> | 452 list<Building> |
323 Skyline::internal_build_skyline (list<Box> *boxes, Real horizon_padding, Axis ho rizon_axis, Direction sky) | 453 Skyline::internal_build_skyline (list<Building> *buildings) const |
324 { | 454 { |
325 vsize size = boxes->size (); | 455 vsize size = buildings->size (); |
326 | 456 |
327 if (size == 0) | 457 if (size == 0) |
328 { | 458 { |
329 list<Building> result; | 459 list<Building> result; |
330 empty_skyline (&result); | 460 empty_skyline (&result); |
331 return result; | 461 return result; |
332 } | 462 } |
333 else if (size == 1) | 463 else if (size == 1) |
334 { | 464 { |
335 list<Building> result; | 465 list<Building> result; |
336 single_skyline (Building (boxes->front (), horizon_padding, horizon_axis, sky), | 466 single_skyline (buildings->front (), &result); |
337 boxes->front ()[horizon_axis][LEFT] - horizon_padding, | |
338 horizon_padding, &result); | |
339 return result; | 467 return result; |
340 } | 468 } |
341 | 469 |
342 deque<list<Building> > partials; | 470 deque<list<Building> > partials; |
343 boxes->sort (LessThanBox (horizon_axis)); | 471 buildings->sort (LessThanBuilding ()); |
344 while (!boxes->empty ()) | 472 while (!buildings->empty ()) |
345 partials.push_back (non_overlapping_skyline (boxes, horizon_padding, horizon _axis, sky)); | 473 partials.push_back (non_overlapping_skyline (buildings)); |
346 | 474 |
347 /* we'd like to say while (partials->size () > 1) but that's O (n). | 475 /* we'd like to say while (partials->size () > 1) but that's O (n). |
348 Instead, we exit in the middle of the loop */ | 476 Instead, we exit in the middle of the loop */ |
349 while (!partials.empty ()) | 477 while (!partials.empty ()) |
350 { | 478 { |
351 list<Building> merged; | 479 list<Building> merged; |
352 list<Building> one = partials.front (); | 480 list<Building> one = partials.front (); |
353 partials.pop_front (); | 481 partials.pop_front (); |
354 if (partials.empty ()) | 482 if (partials.empty ()) |
355 return one; | 483 return one; |
(...skipping 25 matching lines...) Expand all Loading... | |
381 } | 509 } |
382 } | 510 } |
383 | 511 |
384 Skyline::Skyline (Direction sky) | 512 Skyline::Skyline (Direction sky) |
385 { | 513 { |
386 sky_ = sky; | 514 sky_ = sky; |
387 empty_skyline (&buildings_); | 515 empty_skyline (&buildings_); |
388 } | 516 } |
389 | 517 |
390 /* | 518 /* |
391 build padded skyline from an existing skyline with padding | 519 Build skyline from a set of boxes. |
392 added to it. | |
393 */ | |
394 | 520 |
395 Skyline::Skyline (Skyline const &src, Real horizon_padding, Axis /*a*/) | 521 Boxes should have fatness in the horizon_axis, otherwise they are ignored. |
522 */ | |
523 Skyline::Skyline (vector<Box> const &boxes, Axis horizon_axis, Direction sky) | |
396 { | 524 { |
397 /* | 525 list<Building> buildings; |
398 We extract boxes from the skyline, then build a new skyline from | |
399 the boxes. | |
400 A box is created for every horizontal portion of the skyline | |
401 Because skylines are defined positive, and then inverted if they | |
402 are to be down-facing, we create the new skyline in the UP | |
403 direction, then give it the down direction if needed. | |
404 */ | |
405 Real start = -infinity_f; | |
406 list<Box> boxes; | |
407 | |
408 // establish a baseline box | |
409 // FIXME: This has hardcoded logic, assuming a == X_AXIS! | |
410 boxes.push_back (Box (Interval (-infinity_f, infinity_f), | |
411 Interval (0, 0))); | |
412 list<Building>::const_iterator end = src.buildings_.end (); | |
413 for (list<Building>::const_iterator i = src.buildings_.begin (); i != end; sta rt = i->end_, i++) | |
414 if ((i->slope_ == 0) && !isinf (i->y_intercept_)) | |
415 boxes.push_back (Box (Interval (start, i->end_), | |
416 Interval (-infinity_f, i->y_intercept_))); | |
417 buildings_ = internal_build_skyline (&boxes, horizon_padding, X_AXIS, UP); | |
418 sky_ = src.sky_; | |
419 } | |
420 | |
421 /* | |
422 build skyline from a set of boxes. If horizon_padding > 0, expand all the boxe s | |
423 by that amount and add 45-degree sloped boxes to the edges of each box (of | |
424 width horizon_padding). That is, the total amount of horizontal expansion is | |
425 horizon_padding*4, half of which is sloped and half of which is flat. | |
426 | |
427 Boxes should have fatness in the horizon_axis (after they are expanded by | |
428 horizon_padding), otherwise they are ignored. | |
429 */ | |
430 Skyline::Skyline (vector<Box> const &boxes, Real horizon_padding, Axis horizon_a xis, Direction sky) | |
431 { | |
432 list<Box> filtered_boxes; | |
433 sky_ = sky; | 526 sky_ = sky; |
434 | 527 |
435 Axis vert_axis = other_axis (horizon_axis); | 528 Axis vert_axis = other_axis (horizon_axis); |
436 for (vsize i = 0; i < boxes.size (); i++) | 529 for (vsize i = 0; i < boxes.size (); i++) |
437 { | 530 { |
438 Interval iv = boxes[i][horizon_axis]; | 531 Interval iv = boxes[i][horizon_axis]; |
439 iv.widen (horizon_padding); | |
440 if (iv.length () > EPS && !boxes[i][vert_axis].is_empty ()) | 532 if (iv.length () > EPS && !boxes[i][vert_axis].is_empty ()) |
441 filtered_boxes.push_front (boxes[i]); | 533 buildings.push_front (Building (boxes[i], horizon_axis, sky)); |
442 } | 534 } |
443 | 535 |
444 buildings_ = internal_build_skyline (&filtered_boxes, horizon_padding, horizon _axis, sky); | 536 buildings_ = internal_build_skyline (&buildings); |
445 } | 537 } |
446 | 538 |
447 Skyline::Skyline (Box const &b, Real horizon_padding, Axis horizon_axis, Directi on sky) | 539 /* |
540 build skyline from a set of line segments. | |
541 | |
542 Buildings should have fatness in the horizon_axis, otherwise they are ignored. | |
543 */ | |
544 Skyline::Skyline (vector<Drul_array<Offset> > const &segments, Axis horizon_axis , Direction sky) | |
545 { | |
546 list<Building> buildings; | |
547 sky_ = sky; | |
548 | |
549 for (vsize i = 0; i < segments.size (); i++) | |
550 { | |
551 Drul_array<Offset> const& seg = segments[i]; | |
552 Offset left = seg[LEFT]; | |
553 Offset right = seg[RIGHT]; | |
554 if (left[horizon_axis] > right[horizon_axis]) | |
555 swap (left, right); | |
556 | |
557 Real x1 = left[horizon_axis]; | |
558 Real x2 = right[horizon_axis]; | |
559 Real y1 = left[other_axis (horizon_axis)] * sky; | |
560 Real y2 = right[other_axis (horizon_axis)] * sky; | |
561 | |
562 if (x1 + EPS < x2) | |
563 buildings.push_back (Building (x1, y1, y2, x2)); | |
564 } | |
565 | |
566 buildings_ = internal_build_skyline (&buildings); | |
567 } | |
568 | |
569 Skyline::Skyline (vector<Skyline_pair> const &skypairs, Direction sky) | |
448 { | 570 { |
449 sky_ = sky; | 571 sky_ = sky; |
450 Building front (b, horizon_padding, horizon_axis, sky); | 572 |
451 single_skyline (front, b[horizon_axis][LEFT] - horizon_padding, | 573 deque<Skyline> partials; |
452 horizon_padding, &buildings_); | 574 for (vsize i = 0; i < skypairs.size (); i++) |
575 partials.push_back (Skyline ((skypairs[i])[sky])); | |
576 | |
577 while (partials.size () > 1) | |
578 { | |
579 Skyline one = partials.front (); | |
580 partials.pop_front (); | |
581 Skyline two = partials.front (); | |
582 partials.pop_front (); | |
583 · | |
dak
2012/07/09 08:42:16
Whitespace in empty line.
| |
584 one.merge (two); | |
585 partials.push_back (one); | |
586 } | |
587 | |
588 if (partials.size ()) | |
589 buildings_.swap (partials.front ().buildings_); | |
590 else | |
591 buildings_.clear (); | |
592 } | |
593 | |
594 Skyline::Skyline (Box const &b, Axis horizon_axis, Direction sky) | |
595 { | |
596 sky_ = sky; | |
597 Building front (b, horizon_axis, sky); | |
598 single_skyline (front, &buildings_); | |
453 } | 599 } |
454 | 600 |
455 void | 601 void |
456 Skyline::merge (Skyline const &other) | 602 Skyline::merge (Skyline const &other) |
457 { | 603 { |
458 assert (sky_ == other.sky_); | 604 assert (sky_ == other.sky_); |
459 | 605 |
606 if (other.is_empty ()) | |
607 return; | |
608 | |
609 if (is_empty ()) | |
610 { | |
611 buildings_ = other.buildings_; | |
612 return; | |
613 } | |
614 | |
460 list<Building> other_bld (other.buildings_); | 615 list<Building> other_bld (other.buildings_); |
461 list<Building> my_bld; | 616 list<Building> my_bld; |
462 my_bld.splice (my_bld.begin (), buildings_); | 617 my_bld.splice (my_bld.begin (), buildings_); |
463 internal_merge_skyline (&other_bld, &my_bld, &buildings_); | 618 internal_merge_skyline (&other_bld, &my_bld, &buildings_); |
464 } | 619 } |
465 | 620 |
466 void | 621 void |
467 Skyline::insert (Box const &b, Real horizon_padding, Axis a) | 622 Skyline::insert (Box const &b, Axis a) |
468 { | 623 { |
469 list<Building> other_bld; | 624 list<Building> other_bld; |
470 list<Building> my_bld; | 625 list<Building> my_bld; |
471 | 626 |
472 if (isnan (b[other_axis (a)][LEFT]) | 627 if (isnan (b[other_axis (a)][LEFT]) |
473 || isnan (b[other_axis (a)][RIGHT])) | 628 || isnan (b[other_axis (a)][RIGHT])) |
474 { | 629 { |
475 programming_error ("insane box for skyline"); | 630 programming_error ("insane box for skyline"); |
476 return; | 631 return; |
477 } | 632 } |
478 | 633 |
479 /* do the same filtering as in Skyline (vector<Box> const&, etc.) */ | 634 /* do the same filtering as in Skyline (vector<Box> const&, etc.) */ |
480 Interval iv = b[a]; | 635 Interval iv = b[a]; |
481 iv.widen (horizon_padding); | |
482 if (iv.length () <= EPS || b[other_axis (a)].is_empty ()) | 636 if (iv.length () <= EPS || b[other_axis (a)].is_empty ()) |
483 return; | 637 return; |
484 | 638 |
485 my_bld.splice (my_bld.begin (), buildings_); | 639 my_bld.splice (my_bld.begin (), buildings_); |
486 single_skyline (Building (b, horizon_padding, a, sky_), b[a][LEFT] - horizon_p adding, | 640 single_skyline (Building (b, a, sky_), &other_bld); |
487 horizon_padding, &other_bld); | |
488 internal_merge_skyline (&other_bld, &my_bld, &buildings_); | 641 internal_merge_skyline (&other_bld, &my_bld, &buildings_); |
489 } | 642 } |
490 | 643 |
491 void | 644 void |
492 Skyline::raise (Real r) | 645 Skyline::raise (Real r) |
493 { | 646 { |
494 list<Building>::iterator end = buildings_.end (); | 647 list<Building>::iterator end = buildings_.end (); |
495 for (list<Building>::iterator i = buildings_.begin (); i != end; i++) | 648 for (list<Building>::iterator i = buildings_.begin (); i != end; i++) |
496 i->y_intercept_ += sky_ * r; | 649 i->y_intercept_ += sky_ * r; |
497 } | 650 } |
498 | 651 |
499 void | 652 void |
500 Skyline::shift (Real s) | 653 Skyline::shift (Real s) |
501 { | 654 { |
502 list<Building>::iterator end = buildings_.end (); | 655 list<Building>::iterator end = buildings_.end (); |
503 for (list<Building>::iterator i = buildings_.begin (); i != end; i++) | 656 for (list<Building>::iterator i = buildings_.begin (); i != end; i++) |
504 { | 657 { |
658 i->start_ += s; | |
505 i->end_ += s; | 659 i->end_ += s; |
506 i->y_intercept_ -= s * i->slope_; | 660 i->y_intercept_ -= s * i->slope_; |
507 } | 661 } |
508 } | 662 } |
509 | 663 |
510 Real | 664 Real |
511 Skyline::distance (Skyline const &other, Real horizon_padding) const | 665 Skyline::distance (Skyline const &other, Real horizon_padding) const |
512 { | 666 { |
513 Real dummy; | 667 Real dummy; |
514 return internal_distance (other, horizon_padding, &dummy); | 668 return internal_distance (other, horizon_padding, &dummy); |
515 } | 669 } |
516 | 670 |
517 Real | 671 Real |
518 Skyline::touching_point (Skyline const &other, Real horizon_padding) const | 672 Skyline::touching_point (Skyline const &other, Real horizon_padding) const |
519 { | 673 { |
520 Real touch; | 674 Real touch; |
521 internal_distance (other, horizon_padding, &touch); | 675 internal_distance (other, horizon_padding, &touch); |
522 return touch; | 676 return touch; |
523 } | 677 } |
524 | 678 |
525 Real | 679 Real |
526 Skyline::internal_distance (Skyline const &other, Real horizon_padding, Real *to uch_point) const | 680 Skyline::internal_distance (Skyline const &other, Real horizon_padding, Real *to uch_point) const |
527 { | 681 { |
682 if (horizon_padding == 0.0) | |
683 return internal_distance (other, touch_point); | |
684 | |
685 // Note that it is not necessary to build a padded version of other, | |
686 // because the same effect can be achieved just by doubling horizon_padding. | |
687 Skyline padded_this = padded (horizon_padding); | |
688 return padded_this.internal_distance (other, touch_point); | |
689 } | |
690 | |
691 | |
692 Skyline | |
693 Skyline::padded (Real horizon_padding) const | |
694 { | |
695 list<Building> pad_buildings; | |
696 for (list<Building>::const_iterator i = buildings_.begin (); i != buildings_.e nd (); ++i) | |
697 { | |
698 if (i->start_ > -infinity_f) | |
699 { | |
700 Real height = i->height (i->start_); | |
701 if (height > -infinity_f) | |
702 { | |
703 // Add the sloped building that pads the left side of the current building. | |
704 Real start = i->start_ - 2*horizon_padding; | |
705 Real end = i->start_ - horizon_padding; | |
706 pad_buildings.push_back (Building (start, height - horizon_padding , height, end)); | |
707 | |
708 // Add the flat building that pads the left side of the current bu ilding. | |
709 start = i->start_ - horizon_padding; | |
710 end = i->start_;··· | |
dak
2012/07/09 08:42:16
Trailing whitespace.
| |
711 pad_buildings.push_back (Building (start, height, height, end));·················· | |
dak
2012/07/09 08:42:16
Trailing whitespace.
| |
712 } | |
713 } | |
714 | |
715 if (i->end_ < infinity_f) | |
716 { | |
717 Real height = i->height (i->end_); | |
718 if (height > -infinity_f) | |
719 { | |
720 // Add the flat building that pads the right side of the current b uilding. | |
721 Real start = i->end_; | |
722 Real end = start + horizon_padding; | |
723 pad_buildings.push_back (Building (start, height, height, end)); | |
724 | |
725 // Add the sloped building that pads the right side of the current building. | |
726 start = end; | |
727 end += horizon_padding; | |
728 pad_buildings.push_back (Building (start, height, height - horizon _padding, end));············ | |
dak
2012/07/09 08:42:16
Trailing whitespace.
| |
729 } | |
730 } | |
731 } | |
732 | |
733 // The buildings may be overlapping, so resolve that. | |
734 list<Building> pad_skyline = internal_build_skyline (&pad_buildings); | |
735 | |
736 // Merge the padding with the original, to make a new skyline. | |
737 Skyline padded (sky_); | |
738 list<Building> my_buildings = buildings_; | |
739 padded.buildings_.clear (); | |
740 internal_merge_skyline (&pad_skyline, &my_buildings, &padded.buildings_); | |
741 | |
742 return padded; | |
743 } | |
744 | |
745 Real | |
746 Skyline::internal_distance (Skyline const &other, Real *touch_point) const | |
747 { | |
528 assert (sky_ == -other.sky_); | 748 assert (sky_ == -other.sky_); |
529 | 749 |
530 Skyline const *padded_this = this; | |
531 Skyline const *padded_other = &other; | |
532 bool created_tmp_skylines = false; | |
533 | |
534 /* | 750 /* |
535 For systems, padding is not added at creation time. Padding is | 751 For systems, padding is not added at creation time. Padding is |
536 added to AxisGroup objects when outside-staff objects are added. | 752 added to AxisGroup objects when outside-staff objects are added. |
537 Thus, when we want to place systems with horizontal padding, | 753 Thus, when we want to place systems with horizontal padding, |
538 we do it at distance calculation time. | 754 we do it at distance calculation time. |
539 */ | 755 */ |
540 if (horizon_padding != 0.0) | |
541 { | |
542 padded_this = new Skyline (*padded_this, horizon_padding, X_AXIS); | |
543 padded_other = new Skyline (*padded_other, horizon_padding, X_AXIS); | |
544 created_tmp_skylines = true; | |
545 } | |
546 | 756 |
547 list<Building>::const_iterator i = padded_this->buildings_.begin (); | 757 list<Building>::const_iterator i = buildings_.begin (); |
548 list<Building>::const_iterator j = padded_other->buildings_.begin (); | 758 list<Building>::const_iterator j = other.buildings_.begin (); |
549 | 759 |
550 Real dist = -infinity_f; | 760 Real dist = -infinity_f; |
551 Real start = -infinity_f; | 761 Real start = -infinity_f; |
552 Real touch = -infinity_f; | 762 Real touch = -infinity_f; |
553 while (i != padded_this->buildings_.end () && j != padded_other->buildings_.en d ()) | 763 while (i != buildings_.end () && j != other.buildings_.end ()) |
554 { | 764 { |
555 Real end = min (i->end_, j->end_); | 765 Real end = min (i->end_, j->end_); |
556 Real start_dist = i->height (start) + j->height (start); | 766 Real start_dist = i->height (start) + j->height (start); |
557 Real end_dist = i->height (end) + j->height (end); | 767 Real end_dist = i->height (end) + j->height (end); |
558 dist = max (dist, max (start_dist, end_dist)); | 768 dist = max (dist, max (start_dist, end_dist)); |
559 | 769 |
560 if (end_dist == dist) | 770 if (end_dist == dist) |
561 touch = end; | 771 touch = end; |
562 else if (start_dist == dist) | 772 else if (start_dist == dist) |
563 touch = start; | 773 touch = start; |
564 | 774 |
565 if (i->end_ <= j->end_) | 775 if (i->end_ <= j->end_) |
566 i++; | 776 i++; |
567 else | 777 else |
568 j++; | 778 j++; |
569 start = end; | 779 start = end; |
570 } | 780 } |
571 | 781 |
572 if (created_tmp_skylines) | |
573 { | |
574 delete padded_this; | |
575 delete padded_other; | |
576 } | |
577 | |
578 *touch_point = touch; | 782 *touch_point = touch; |
579 return dist; | 783 return dist; |
580 } | 784 } |
581 | 785 |
786 Skyline_intersection_info | |
787 Skyline::intersects (Skyline const &other) const | |
788 { | |
789 assert (sky_ == -other.sky_); | |
790 | |
791 /* | |
792 For systems, padding is not added at creation time. Padding is | |
793 added to AxisGroup objects when outside-staff objects are added. | |
794 Thus, when we want to place systems with horizontal padding, | |
795 we do it at distance calculation time. | |
796 */ | |
797 | |
798 list<Building>::const_iterator i = buildings_.begin (); | |
799 list<Building>::const_iterator j = other.buildings_.begin (); | |
800 | |
801 Real start = -infinity_f; | |
802 Drul_array<bool> intersections (false, false); | |
803 while (i != buildings_.end () && j != other.buildings_.end ()) | |
804 { | |
805 Real end = min (i->end_, j->end_); | |
806 Real start_dist = i->height (start) + j->height (start); | |
807 Real end_dist = i->height (end) + j->height (end); | |
808 if (!isinf (start_dist)) | |
809 { | |
810 if (start_dist == 0.0) | |
811 return INTERSECTS; | |
812 intersections[Direction (sign (start_dist))] = true; | |
813 } | |
814 if (!isinf (end_dist)) | |
815 { | |
816 if (end_dist == 0.0) | |
817 return INTERSECTS; | |
818 intersections[Direction (sign (end_dist))] = true; | |
819 } | |
820 if (intersections[DOWN] && intersections[UP]) | |
821 return INTERSECTS; | |
822 | |
823 if (i->end_ <= j->end_) | |
824 i++; | |
825 else | |
826 j++; | |
827 start = end; | |
828 } | |
829 | |
830 if (intersections[DOWN]) | |
831 return ALWAYS_LESS; | |
832 if (intersections[UP]) | |
833 return ALWAYS_GREATER; | |
834 return NOT_ENOUGH_INFO;···· | |
dak
2012/07/09 08:42:16
Trailing whitespace.
| |
835 } | |
836 | |
837 // changes the direction that the skyline is pointing | |
838 void | |
839 Skyline::invert () | |
840 { | |
841 list<Building>::iterator i; | |
842 for (i = buildings_.begin (); i != buildings_.end (); i++) | |
843 if (!isinf (i->y_intercept_)) | |
844 { | |
845 i->y_intercept_ *= -1; | |
846 i->slope_ *= -1; | |
847 } | |
848 | |
849 sky_ = -sky_; | |
850 } | |
851 | |
582 Real | 852 Real |
583 Skyline::height (Real airplane) const | 853 Skyline::height (Real airplane) const |
584 { | 854 { |
585 assert (!isinf (airplane)); | 855 assert (!isinf (airplane)); |
586 | 856 |
587 list<Building>::const_iterator i; | 857 list<Building>::const_iterator i; |
588 for (i = buildings_.begin (); i != buildings_.end (); i++) | 858 for (i = buildings_.begin (); i != buildings_.end (); i++) |
589 { | 859 { |
590 if (i->end_ >= airplane) | 860 if (i->end_ >= airplane) |
591 return sky_ * i->height (airplane); | 861 return sky_ * i->height (airplane); |
592 } | 862 } |
593 | 863 |
594 assert (0); | 864 assert (0); |
595 return 0; | 865 return 0; |
596 } | 866 } |
597 | 867 |
598 Real | 868 Real |
599 Skyline::max_height () const | 869 Skyline::max_height () const |
600 { | 870 { |
601 Skyline s (-sky_); | 871 Real ret = -infinity_f; |
602 s.set_minimum_height (0); | 872 |
603 return sky_ * distance (s); | 873 list<Building>::const_iterator i; |
874 for (i = buildings_.begin (); i != buildings_.end (); ++i) | |
875 { | |
876 ret = max (ret, i->height (i->start_)); | |
877 ret = max (ret, i->height (i->end_)); | |
878 } | |
879 | |
880 return sky_ * ret; | |
604 } | 881 } |
605 | 882 |
606 Real | 883 Real |
607 Skyline::max_height_position () const | 884 Skyline::max_height_position () const |
608 { | 885 { |
609 Skyline s (-sky_); | 886 Skyline s (-sky_); |
610 s.set_minimum_height (0); | 887 s.set_minimum_height (0); |
611 return touching_point (s); | 888 return touching_point (s); |
612 } | 889 } |
613 | 890 |
(...skipping 19 matching lines...) Expand all Loading... | |
633 start = i->end_; | 910 start = i->end_; |
634 } | 911 } |
635 | 912 |
636 if (horizon_axis == Y_AXIS) | 913 if (horizon_axis == Y_AXIS) |
637 for (vsize i = 0; i < out.size (); i++) | 914 for (vsize i = 0; i < out.size (); i++) |
638 out[i] = out[i].swapped (); | 915 out[i] = out[i].swapped (); |
639 | 916 |
640 return out; | 917 return out; |
641 } | 918 } |
642 | 919 |
920 // Returns the smallest (non-negative) shift in the given | |
921 // direction which will result in THIS and OTHER not overlapping. | |
922 // Warning: this function is O(n^2 log n). Use sparingly. | |
923 Real | |
924 Skyline::smallest_shift (Skyline const& other, | |
925 Direction d, | |
926 Real horizon_padding, | |
927 Real vertical_padding) const | |
928 { | |
929 // If one or both of the paddings is zero, this can | |
930 // be optimized... | |
931 Skyline padded_me = padded (horizon_padding); | |
932 padded_me.raise (vertical_padding); | |
933 | |
934 list<Building>::const_iterator i = padded_me.buildings_.begin (); | |
935 list<Building>::const_iterator j = other.buildings_.begin (); | |
936 list<Building>::const_iterator i_end = padded_me.buildings_.end (); | |
937 list<Building>::const_iterator j_end = other.buildings_.end (); | |
938 | |
939 // Find all shifts that are not allowed. | |
940 vector<Interval> forbidden_shifts; | |
941 for (; i != i_end; ++i) | |
942 if (i->y_intercept_ != -infinity_f) | |
943 for (j = other.buildings_.begin (); j != j_end; ++j) | |
944 { | |
945 Interval iv = i->overlapping_shift_interval (*j); | |
946 if (!iv.is_empty ()) | |
947 forbidden_shifts.push_back (iv); | |
948 } | |
949 | |
950 // Now comes the trick: we want to find the smallest point | |
951 // that is not in the union of forbidden_shifts. We can represent | |
952 // the union of forbidden_shifts as a skyline, where a point is | |
953 // allowed if it has height -infinity_f and forbidden otherwise. | |
954 vector<Box> boxes; | |
955 for (vector<Interval>::iterator k = forbidden_shifts.begin (); | |
956 k != forbidden_shifts.end (); ++k) | |
957 boxes.push_back (Box (*k, Interval(-1, 0))); | |
958 Skyline s (boxes, X_AXIS, UP); | |
959 | |
960 // Find the smallest (ie. closest to zero, in the appropriate direction) | |
961 // coordinate where the height of s is -infinity_f. | |
962 Real last_good_point = -infinity_f; | |
963 for (i = s.buildings_.begin (); i != s.buildings_.end (); ++i) | |
964 { | |
965 if (d == LEFT && i->start_ > 0) | |
966 return last_good_point; | |
967 | |
968 if (i->y_intercept_ == -infinity_f) | |
969 { | |
970 if (i->start_ <= 0 && i->end_ >= 0) | |
971 return 0; | |
972 if (d == RIGHT && i->start_ >= 0) | |
973 return i->start_; | |
974 | |
975 last_good_point = i->end_; | |
976 } | |
977 } | |
978 | |
979 return infinity_f * d; | |
980 } | |
981 | |
982 Real | |
983 Skyline::left () const | |
984 { | |
985 for (list<Building>::const_iterator i (buildings_.begin ()); | |
986 i != buildings_.end (); i++) | |
987 if (i->y_intercept_ > -infinity_f) | |
988 return i->start_; | |
989 | |
990 return infinity_f; | |
991 } | |
992 | |
993 Real | |
994 Skyline::right () const | |
995 { | |
996 for (list<Building>::const_reverse_iterator i (buildings_.rbegin ()); | |
997 i != buildings_.rend (); ++i) | |
998 if (i->y_intercept_ > -infinity_f) | |
999 return i->end_; | |
1000 | |
1001 return -infinity_f; | |
1002 } | |
1003 | |
643 bool | 1004 bool |
644 Skyline::is_empty () const | 1005 Skyline::is_empty () const |
645 { | 1006 { |
1007 if (!buildings_.size ()) | |
1008 return true; | |
646 Building b = buildings_.front (); | 1009 Building b = buildings_.front (); |
647 return b.end_ == infinity_f && b.y_intercept_ == -infinity_f; | 1010 return b.end_ == infinity_f && b.y_intercept_ == -infinity_f; |
648 } | 1011 } |
649 | 1012 |
1013 bool | |
1014 Skyline::is_singleton () const | |
1015 { | |
1016 return buildings_.size () == 3; | |
1017 } | |
1018 | |
650 void | 1019 void |
651 Skyline::clear () | 1020 Skyline::clear () |
652 { | 1021 { |
653 buildings_.clear (); | 1022 buildings_.clear (); |
654 empty_skyline (&buildings_); | 1023 empty_skyline (&buildings_); |
655 } | 1024 } |
656 | 1025 |
1026 string | |
1027 Skyline::intersection_info_to_string (Skyline_intersection_info sii) | |
1028 { | |
1029 if (sii == INTERSECTS) | |
1030 return "intersection"; | |
1031 if (sii == ALWAYS_GREATER) | |
1032 return "alwaysGreater"; | |
1033 if (sii == ALWAYS_LESS) | |
1034 return "alwaysLess"; | |
1035 if (sii == NOT_ENOUGH_INFO) | |
1036 return "notEnoughInfo"; | |
1037 | |
1038 assert (1 == 0); | |
1039 return "veryBad"; | |
1040 } | |
1041 | |
1042 Direction | |
1043 Skyline::intersection_info_to_direction (Skyline_intersection_info sii) | |
1044 { | |
1045 if (sii == INTERSECTS) | |
1046 return CENTER; | |
1047 if (sii == ALWAYS_GREATER) | |
1048 return UP; | |
1049 if (sii == ALWAYS_LESS) | |
1050 return DOWN; | |
1051 if (sii == NOT_ENOUGH_INFO) | |
1052 return CENTER; | |
1053 | |
1054 assert (1 == 0); | |
1055 return CENTER; | |
1056 } | |
1057 | |
657 /****************************************************************/ | 1058 /****************************************************************/ |
658 | 1059 |
659 IMPLEMENT_SIMPLE_SMOBS (Skyline); | 1060 IMPLEMENT_SIMPLE_SMOBS (Skyline); |
660 IMPLEMENT_TYPE_P (Skyline, "ly:skyline?"); | 1061 IMPLEMENT_TYPE_P (Skyline, "ly:skyline?"); |
661 IMPLEMENT_DEFAULT_EQUAL_P (Skyline); | 1062 IMPLEMENT_DEFAULT_EQUAL_P (Skyline); |
662 | 1063 |
663 SCM | 1064 SCM |
664 Skyline::mark_smob (SCM s) | 1065 Skyline::mark_smob (SCM s) |
665 { | 1066 { |
666 ASSERT_LIVE_IS_ALLOWED (s); | 1067 ASSERT_LIVE_IS_ALLOWED (s); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
728 return scm_from_double (Skyline::unsmob (skyline_scm)->max_height_position ()) ; | 1129 return scm_from_double (Skyline::unsmob (skyline_scm)->max_height_position ()) ; |
729 } | 1130 } |
730 | 1131 |
731 MAKE_SCHEME_CALLBACK (Skyline, get_height, 2) | 1132 MAKE_SCHEME_CALLBACK (Skyline, get_height, 2) |
732 SCM | 1133 SCM |
733 Skyline::get_height (SCM skyline_scm, SCM x_scm) | 1134 Skyline::get_height (SCM skyline_scm, SCM x_scm) |
734 { | 1135 { |
735 Real x = robust_scm2double (x_scm, 0.0); | 1136 Real x = robust_scm2double (x_scm, 0.0); |
736 return scm_from_double (Skyline::unsmob (skyline_scm)->height (x)); | 1137 return scm_from_double (Skyline::unsmob (skyline_scm)->height (x)); |
737 } | 1138 } |
OLD | NEW |