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 int 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, int y, int x, int width) {
111 int 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];
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 int 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 int 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) {
268 if (im->bits == i_8_bits && fill->fill_with_color) {
269 i_color *line = mymalloc(sizeof(i_color) * im->xsize);
270 i_color *work = NULL;
272 work = mymalloc(sizeof(i_color) * im->xsize);
273 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
274 i_int_hline_entry *entry = hlines->entries[y - hlines->start_y];
276 for (i = 0; i < entry->count; ++i) {
277 i_int_hline_seg *seg = entry->segs + i;
278 int width = seg->x_limit-seg->minx;
281 i_glin(im, seg->minx, seg->x_limit, y, line);
282 (fill->fill_with_color)(fill, seg->minx, y, width,
284 (fill->combine)(line, work, im->channels, width);
287 (fill->fill_with_color)(fill, seg->minx, y, width,
290 i_plin(im, seg->minx, seg->x_limit, y, line);
300 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
301 i_fcolor *work = NULL;
303 work = mymalloc(sizeof(i_fcolor) * im->xsize);
304 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
305 i_int_hline_entry *entry = hlines->entries[y - hlines->start_y];
307 for (i = 0; i < entry->count; ++i) {
308 i_int_hline_seg *seg = entry->segs + i;
309 int width = seg->x_limit-seg->minx;
311 if (fill->combinef) {
312 i_glinf(im, seg->minx, seg->x_limit, y, line);
313 (fill->fill_with_fcolor)(fill, seg->minx, y, width,
315 (fill->combinef)(line, work, im->channels, width);
318 (fill->fill_with_fcolor)(fill, seg->minx, y, width,
321 i_plinf(im, seg->minx, seg->x_limit, y, line);
337 Tony Cook <tony@imager.perl.org>