2 skyline.cc -- implement Skyline_entry and funcs.
4 source file of the GNU LilyPond music typesetter
6 (c) 2002--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
13 A skyline is a shape of the form:
26 This file deals with building such skyline structure, and computing
27 the minimum distance between two opposing skylines.
30 Invariants for a skyline:
32 skyline[...].width_ forms a partition of the real interval, where
33 the segments are adjacent, and ascending. Hence we have
35 skyline.top().width_[RIGHT] = inf
36 skyline[0].width_[LEFT] = -inf
41 const Real EPS
= 1e-12;
44 TODO: avoid unnecessary fragmentation.
46 This is O(n^2), searching and insertion. Could be O(n log n) with
50 insert_extent_into_skyline (Array
<Skyline_entry
> *line
, Box b
, Axis line_axis
,
53 Interval extent
= b
[line_axis
];
57 Real stick_out
= b
[other_axis (line_axis
)][d
];
60 Intersect each segment of LINE with EXTENT, and if non-empty, insert relevant segments.
62 for (int i
= line
->size(); i
--;)
64 Interval w
= line
->elem(i
).width_
;
67 if (extent
[LEFT
] >= w
[RIGHT
])
70 Real my_height
= line
->elem(i
).height_
;
74 && d
* (my_height
- stick_out
) < 0)
76 Interval
e1 (line
->elem(i
).width_
[LEFT
], extent
[LEFT
]);
77 Interval
e3 (extent
[RIGHT
], line
->elem(i
).width_
[RIGHT
]);
79 if (!e3
.empty_b () && e3
.length() > EPS
)
80 line
->insert (Skyline_entry (e3
, my_height
), i
+1);
82 line
->elem_ref(i
).height_
= stick_out
;
83 line
->elem_ref(i
).width_
= w
;
84 if (!e1
.empty_b () && e1
.length() > EPS
)
85 line
->insert (Skyline_entry (e1
, my_height
), i
);
94 empty_skyline (Direction d
)
96 Array
<Skyline_entry
> skyline
;
103 e
.height_
= -d
* infinity_f
;
109 extents_to_skyline (Array
<Box
> const &extents
, Axis a
, Direction d
)
112 Array
<Skyline_entry
> skyline
= empty_skyline(d
);
115 This makes a cubic algorithm (array insertion is O(n),
116 searching the array dumbly is O(n), and for n items, we get O(n^3).)
118 We could do a lot better (n log (n), using a balanced tree) but
119 that seems overkill for now.
121 for (int j
= extents
.size(); j
--; )
122 insert_extent_into_skyline (&skyline
, extents
[j
], a
, d
);
129 minimum distance that can be achieved between baselines. "Clouds" is
130 a skyline pointing down.
132 This is an O(n) algorithm.
135 skyline_meshing_distance (Array
<Skyline_entry
> const &buildings
,
136 Array
<Skyline_entry
> const &clouds
)
138 int i
= buildings
.size () -1;
139 int j
= clouds
.size() -1;
141 Real distance
= - infinity_f
;
143 while (i
> 0 || j
> 0)
145 Interval w
= buildings
[i
].width_
;
146 w
.intersect(clouds
[j
].width_
);
149 distance
= distance
>? (buildings
[i
].height_
- clouds
[j
].height_
);
151 if (i
>0 && buildings
[i
].width_
[LEFT
] >= clouds
[j
].width_
[LEFT
])
155 else if (j
> 0 && buildings
[i
].width_
[LEFT
] <= clouds
[j
].width_
[LEFT
])
164 Skyline_entry::Skyline_entry()
169 Skyline_entry::Skyline_entry (Interval i
, Real r
)