1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Utility Sources
4 // Copyright (C) 2000-2002 by Denton Woods
5 // Last modified: 07/09/2002 <--Y2K Compliant! =]
6 //
7 // Filename: src-ILU/src/ilu_region.c
8 //
9 // Description: Creates an image region.
10 //
11 //-----------------------------------------------------------------------------
12
13
14 #include "ilu_internal.h"
15 #include "ilu_region.h"
16
17 ILpointi *RegionPointsi = NULL;
18 ILpointf *RegionPointsf = NULL;
19 ILuint PointNum = 0;
20 ILubyte *iRegionMask = NULL;
21
iluRegionfv(ILpointf * Points,ILuint n)22 void ILAPIENTRY iluRegionfv(ILpointf *Points, ILuint n)
23 {
24 if (Points == NULL || n == 0) {
25 ifree(RegionPointsi);
26 ifree(RegionPointsf);
27 RegionPointsf = NULL;
28 PointNum = 0;
29 return;
30 }
31 if (n < 3) {
32 ilSetError(ILU_INVALID_PARAM);
33 return;
34 }
35 ifree(RegionPointsi);
36 ifree(RegionPointsf);
37 RegionPointsf = (ILpointf*)ialloc(sizeof(ILpointf) * n);
38 if (RegionPointsf == NULL)
39 return;
40 memcpy(RegionPointsf, Points, sizeof(ILpointi) * n);
41 PointNum = n;
42 return;
43 }
44
45
iluRegioniv(ILpointi * Points,ILuint n)46 void ILAPIENTRY iluRegioniv(ILpointi *Points, ILuint n)
47 {
48 if (Points == NULL || n == 0) {
49 ifree(RegionPointsi);
50 ifree(RegionPointsf);
51 RegionPointsi = NULL;
52 PointNum = 0;
53 return;
54 }
55 if (n < 3) {
56 ilSetError(ILU_INVALID_PARAM);
57 return;
58 }
59 ifree(RegionPointsi);
60 ifree(RegionPointsf);
61 RegionPointsi = (ILpointi*)ialloc(sizeof(ILpointi) * n);
62 if (RegionPointsi == NULL)
63 return;
64 memcpy(RegionPointsi, Points, sizeof(ILpointi) * n);
65 PointNum = n;
66 return;
67 }
68
69
70 // Inserts edge into list in order of increasing xIntersect field.
InsertEdge(Edge * list,Edge * edge)71 void InsertEdge(Edge *list, Edge *edge)
72 {
73 Edge *p, *q = list;
74
75 p = q->next;
76 while (p != NULL) {
77 if (edge->xIntersect < p->xIntersect) {
78 p = NULL;
79 }
80 else {
81 q = p;
82 p = p->next;
83 }
84 }
85 edge->next = q->next;
86 q->next = edge;
87 }
88
89
90 // For an index, return y-coordinate of next nonhorizontal line
yNext(ILint k,ILint cnt,ILpointi * pts)91 ILint yNext(ILint k, ILint cnt, ILpointi *pts)
92 {
93 ILint j;
94
95 if ((k+1) > (cnt-1))
96 j = 0;
97 else
98 j = k + 1;
99
100 while (pts[k].y == pts[j].y) {
101 if ((j+1) > (cnt-1))
102 j = 0;
103 else
104 j++;
105 }
106
107 return pts[j].y;
108 }
109
110
111 // Store lower-y coordinate and inverse slope for each edge. Adjust
112 // and store upper-y coordinate for edges that are the lower member
113 // of a monotonically increasing or decreasing pair of edges
MakeEdgeRec(ILpointi lower,ILpointi upper,ILint yComp,Edge * edge,Edge * edges[])114 void MakeEdgeRec(ILpointi lower, ILpointi upper, ILint yComp, Edge *edge, Edge *edges[])
115 {
116 edge->dxPerScan = (ILfloat)(upper.x - lower.x) / (upper.y - lower.y);
117 edge->xIntersect = (ILfloat)lower.x;
118 if (upper.y < yComp)
119 edge->yUpper = upper.y - 1;
120 else
121 edge->yUpper = upper.y;
122
123 InsertEdge(edges[lower.y], edge);
124 }
125
126
BuildEdgeList(ILuint cnt,ILpointi * pts,Edge ** edges)127 void BuildEdgeList(ILuint cnt, ILpointi *pts, Edge **edges)
128 {
129 Edge *edge;
130 ILpointi v1, v2;
131 ILuint i;
132 ILint yPrev = pts[cnt - 2].y;
133
134 v1.x = pts[cnt-1].x;
135 v1.y = pts[cnt-1].y;
136
137 for (i = 0; i < cnt; i++) {
138 v2 = pts[i];
139 if (v1.y != v2.y) { // nonhorizontal line
140 edge = (Edge*)ialloc(sizeof(Edge));
141 if (v1.y < v2.y) { // up-going edge
142 MakeEdgeRec(v1, v2, yNext(i, cnt, pts), edge, edges);
143 }
144 else { // down-going edge
145 MakeEdgeRec(v2, v1, yPrev, edge, edges);
146 }
147 }
148 yPrev = v1.y;
149 v1 = v2;
150 }
151 }
152
153
BuildActiveList(ILint scan,Edge * active,Edge * edges[])154 void BuildActiveList(ILint scan, Edge *active, Edge *edges[])
155 {
156 Edge *p, *q;
157
158 p = edges[scan]->next;
159 while (p) {
160 q = p->next;
161 InsertEdge(active, p);
162 p = q;
163 }
164 }
165
166
167 #define iRegionSetPixel(x,y) (iRegionMask[y * iluCurImage->Width + x] = 1 )
168
169
FillScan(ILint scan,Edge * active)170 void FillScan(ILint scan, Edge *active)
171 {
172 Edge *p1, *p2;
173 ILint i;
174
175 p1 = active->next;
176 while (p1) {
177 p2 = p1->next;
178 for (i = (ILuint)p1->xIntersect; i < p2->xIntersect; i++) {
179 iRegionSetPixel((ILuint)i, scan);
180 }
181 p1 = p2->next;
182 }
183 }
184
185
DeleteAfter(Edge * q)186 void DeleteAfter(Edge *q)
187 {
188 Edge *p = q->next;
189 q->next = p->next;
190 free(p);
191 }
192
193
194 // Delete completed edges. Update 'xIntersect' field for others
UpdateActiveList(ILint scan,Edge * active)195 void UpdateActiveList(ILint scan, Edge *active)
196 {
197 Edge *q = active, *p = active->next;
198
199 while (p) {
200 if (scan >= p->yUpper) {
201 p = p->next;
202 DeleteAfter(q);
203 }
204 else {
205 p->xIntersect = p->xIntersect + p->dxPerScan;
206 q = p;
207 p = p->next;
208 }
209 }
210 }
211
212
ResortActiveList(Edge * active)213 void ResortActiveList(Edge *active)
214 {
215 Edge *q, *p = active->next;
216
217 active->next = NULL;
218 while (p) {
219 q = p->next;
220 InsertEdge(active, p);
221 p = q;
222 }
223 }
224
225
iScanFill()226 ILubyte *iScanFill()
227 {
228 Edge **edges = NULL, *active = NULL/*, *temp*/;
229 ILuint i, scan;
230
231 iRegionMask = NULL;
232
233 if ((RegionPointsi == NULL && RegionPointsf == NULL) || PointNum == 0)
234 return NULL;
235
236 if (RegionPointsf) {
237 RegionPointsi = (ILpointi*)ialloc(sizeof(ILpointi) * PointNum);
238 if (RegionPointsi == NULL)
239 goto error;
240 }
241
242 for (i = 0; i < PointNum; i++) {
243 if (RegionPointsf) {
244 RegionPointsi[i].x = (ILuint)(iluCurImage->Width * RegionPointsf[i].x);
245 RegionPointsi[i].y = (ILuint)(iluCurImage->Height * RegionPointsf[i].y);
246 }
247 if (RegionPointsi[i].x >= (ILint)iluCurImage->Width || RegionPointsi[i].y >= (ILint)iluCurImage->Height)
248 goto error;
249 }
250
251 edges = (Edge**)ialloc(sizeof(Edge*) * iluCurImage->Height);
252 iRegionMask = (ILubyte*)ialloc(iluCurImage->Width * iluCurImage->Height * iluCurImage->Depth);
253 if (edges == NULL || iRegionMask == NULL)
254 goto error;
255 imemclear(iRegionMask, iluCurImage->Width * iluCurImage->Height * iluCurImage->Depth);
256
257 for (i = 0; i < iluCurImage->Height; i++) {
258 edges[i] = (Edge*)ialloc(sizeof(Edge));
259 edges[i]->next = NULL;
260 }
261 BuildEdgeList(PointNum, RegionPointsi, edges);
262 active = (Edge*)ialloc(sizeof(Edge));
263 active->next = NULL;
264
265 for (scan = 0; scan < iluCurImage->Height; scan++) {
266 BuildActiveList(scan, active, edges);
267 if (active->next) {
268 FillScan(scan, active);
269 UpdateActiveList(scan, active);
270 ResortActiveList(active);
271 }
272 }
273
274 // Free edge records that have been allocated.
275 /*for (i = 0; i < iluCurImage->Height; i++) {
276 while (edges[i]) {
277 temp = edges[i]->next;
278 ifree(edges[i]);
279 edges[i] = temp;
280 }
281 }*/
282
283 ifree(edges);
284
285 if (RegionPointsf) {
286 ifree(RegionPointsi);
287 RegionPointsi = NULL;
288 }
289
290 return iRegionMask;
291
292 error:
293 if (RegionPointsf) {
294 ifree(RegionPointsi);
295 RegionPointsi = NULL;
296 }
297
298 // Free edge records that have been allocated.
299
300 ifree(edges);
301 ifree(iRegionMask);
302 return NULL;
303 }
304
305