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