4 #define OVERLAPPED(start1, end1, start2, end2) \
5 (im_max((start1), (start2)) <= im_min((end1), (end2)))
10 hlines.c - implements a "class" for managing sets of horizontal line segments
15 // just for the specified range of y
16 i_int_init_hlines(&hlines, start_y, count_y, start_x, width_x);
17 // to cover a whole image
18 i_int_init_hlines_img(&hlines, img);
19 // add a hline segment, merging into existing
20 i_int_hlines_add(&hlines, y, x, width);
22 // work over the lines
23 for (y = hlines.start; y < hlines.limit; ++y) {
24 i_int_hline_entry *entry = hlines.entries[i];
26 for (i = 0; i < entry->count; ++i) {
27 i_int_hline_seg *seg = entry->segs+i;
28 // do something on line y for seg->minx to x_limit
34 i_int_hlines_destroy(&hlines);
38 Provides a class to manage sets of horizontal line segments. The
39 intent is that when drawing shapes where the algorithm used might
40 cause overlaps we can use this class to resolve the overlaps.
42 Note that segment lists are intended to remain small, if we end up
43 with a need for longer lists we should use different structure for the
48 =item i_int_init_hlines
50 i_int_init_hlines(&hlines, start_y, count_y, start_x, width_x)
52 Initializes the structure based on drawing an object within the given
53 range. Any x or y values outside the given ranges will be ignored.
68 size_t bytes = count_y * sizeof(i_int_hline_entry *);
70 if (bytes / count_y != sizeof(i_int_hline_entry *)) {
71 i_fatal(3, "integer overflow calculating memory allocation\n");
74 hlines->start_y = start_y;
75 hlines->limit_y = start_y + count_y;
76 hlines->start_x = start_x;
77 hlines->limit_x = start_x + width_x;
78 hlines->entries = mymalloc(bytes);
79 memset(hlines->entries, 0, bytes);
83 =item i_int_init_hlines_img
85 i_int_init_hlines_img(img);
87 Initialize a hlines object as if we could potentially draw anywhere on
94 i_int_init_hlines_img(i_int_hlines *hlines, i_img *img)
96 i_int_init_hlines(hlines, 0, img->ysize, 0, img->xsize);
100 =item i_int_hlines_add
102 i_int_hlines_add(hlines, y, x, width)
104 Add to the list, merging with existing entries.
110 i_int_hlines_add(i_int_hlines *hlines, i_img_dim y, i_img_dim x, i_img_dim width) {
111 i_img_dim x_limit = x + width;
114 i_fatal(3, "negative width %d passed to i_int_hlines_add\n", width);
117 /* just return if out of range */
118 if (y < hlines->start_y || y >= hlines->limit_y)
121 if (x >= hlines->limit_x || x_limit < hlines->start_x)
124 /* adjust x to our range */
125 if (x < hlines->start_x)
127 if (x_limit > hlines->limit_x)
128 x_limit = hlines->limit_x;
133 if (hlines->entries[y - hlines->start_y]) {
134 i_int_hline_entry *entry = hlines->entries[y - hlines->start_y];
135 i_img_dim i, found = -1;
137 for (i = 0; i < entry->count; ++i) {
138 i_int_hline_seg *seg = entry->segs + i;
139 if (OVERLAPPED(x, x_limit, seg->minx, seg->x_limit)) {
145 /* ok, we found an overlapping segment, any other overlapping
146 segments need to be merged into the one we found */
147 i_int_hline_seg *merge_seg = entry->segs + found;
149 /* merge in the segment we found */
150 x = im_min(x, merge_seg->minx);
151 x_limit = im_max(x_limit, merge_seg->x_limit);
153 /* look for other overlapping segments */
154 /* this could be a for(), but I'm using continue */
156 while (i < entry->count) {
157 i_int_hline_seg *seg = entry->segs + i;
158 if (OVERLAPPED(x, x_limit, seg->minx, seg->x_limit)) {
159 /* merge this into the current working segment, then
160 delete it by moving the last segment (if this isn't it)
162 x = im_min(x, seg->minx);
163 x_limit = im_max(x_limit, seg->x_limit);
164 if (i < entry->count-1) {
165 *seg = entry->segs[entry->count-1];
179 merge_seg->x_limit = x_limit;
182 i_int_hline_seg *seg;
183 /* add a new segment */
184 if (entry->count == entry->alloc) {
186 size_t alloc = entry->alloc * 3 / 2;
187 entry = myrealloc(entry, sizeof(i_int_hline_entry) +
188 sizeof(i_int_hline_seg) * (alloc - 1));
189 entry->alloc = alloc;
190 hlines->entries[y - hlines->start_y] = entry;
192 seg = entry->segs + entry->count++;
194 seg->x_limit = x_limit;
198 /* make a new one - start with space for 10 */
199 i_int_hline_entry *entry = mymalloc(sizeof(i_int_hline_entry) +
200 sizeof(i_int_hline_seg) * 9);
203 entry->segs[0].minx = x;
204 entry->segs[0].x_limit = x_limit;
205 hlines->entries[y - hlines->start_y] = entry;
210 =item i_int_hlines_destroy
212 i_int_hlines_destroy(&hlines)
214 Releases all memory associated with the structure.
220 i_int_hlines_destroy(i_int_hlines *hlines) {
221 size_t entry_count = hlines->limit_y - hlines->start_y;
224 for (i = 0; i < entry_count; ++i) {
225 if (hlines->entries[i])
226 myfree(hlines->entries[i]);
228 myfree(hlines->entries);
232 =item i_int_hlines_fill_color
234 i_int_hlines_fill(im, hlines, color)
236 Fill the areas given by hlines with color.
242 i_int_hlines_fill_color(i_img *im, i_int_hlines *hlines, const i_color *col) {
245 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
246 i_int_hline_entry *entry = hlines->entries[y - hlines->start_y];
248 for (i = 0; i < entry->count; ++i) {
249 i_int_hline_seg *seg = entry->segs + i;
250 for (x = seg->minx; x < seg->x_limit; ++x) {
251 i_ppix(im, x, y, col);
259 =item i_int_hlines_fill_fill
261 i_int_hlines_fill_fill(im, hlines, fill)
265 i_int_hlines_fill_fill(i_img *im, i_int_hlines *hlines, i_fill_t *fill) {
269 i_render_init(&r, im, im->xsize);
271 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
272 i_int_hline_entry *entry = hlines->entries[y - hlines->start_y];
274 for (i = 0; i < entry->count; ++i) {
275 i_int_hline_seg *seg = entry->segs + i;
276 i_img_dim width = seg->x_limit-seg->minx;
278 i_render_fill(&r, seg->minx, y, width, NULL, fill);
286 if (im->bits == i_8_bits && fill->fill_with_color) {
287 i_color *line = mymalloc(sizeof(i_color) * im->xsize);
288 i_color *work = NULL;
290 work = mymalloc(sizeof(i_color) * im->xsize);
291 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
292 i_int_hline_entry *entry = hlines->entries[y - hlines->start_y];
294 for (i = 0; i < entry->count; ++i) {
295 i_int_hline_seg *seg = entry->segs + i;
296 i_img_dim width = seg->x_limit-seg->minx;
299 i_glin(im, seg->minx, seg->x_limit, y, line);
300 (fill->fill_with_color)(fill, seg->minx, y, width,
302 (fill->combine)(line, work, im->channels, width);
305 (fill->fill_with_color)(fill, seg->minx, y, width,
308 i_plin(im, seg->minx, seg->x_limit, y, line);
318 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
319 i_fcolor *work = NULL;
321 work = mymalloc(sizeof(i_fcolor) * im->xsize);
322 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
323 i_int_hline_entry *entry = hlines->entries[y - hlines->start_y];
325 for (i = 0; i < entry->count; ++i) {
326 i_int_hline_seg *seg = entry->segs + i;
327 i_img_dim width = seg->x_limit-seg->minx;
329 if (fill->combinef) {
330 i_glinf(im, seg->minx, seg->x_limit, y, line);
331 (fill->fill_with_fcolor)(fill, seg->minx, y, width,
333 (fill->combinef)(line, work, im->channels, width);
336 (fill->fill_with_fcolor)(fill, seg->minx, y, width,
339 i_plinf(im, seg->minx, seg->x_limit, y, line);
356 Tony Cook <tonyc@cpan.org>