1 /**
2  ** scanellp.c ---- draw the outline or scan fill an ellipse
3  **
4  ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
5  ** [e-mail: csaba@vuse.vanderbilt.edu]
6  **
7  ** This file is part of the GRX graphics library.
8  **
9  ** The GRX graphics library is free software; you can redistribute it
10  ** and/or modify it under some conditions; see the "copying.grx" file
11  ** for details.
12  **
13  ** This library is distributed in the hope that it will be useful,
14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  **
17  **/
18 
19 #include "libgrx.h"
20 #include "allocate.h"
21 #include "arith.h"
22 #include "clipping.h"
23 #include "shapes.h"
24 
25 #define  MAXR   120             /* max radius for which Bresenham works */
26 
_GrScanEllipse(int xc,int yc,int xa,int ya,GrFiller * f,GrFillArg c,int filled)27 void _GrScanEllipse(int xc,int yc,int xa,int ya,GrFiller *f,GrFillArg c,int filled)
28 {
29 	int x1,x2,y1,y2;
30 	if(xa < 0) xa = (-xa);
31 	if(ya < 0) ya = (-ya);
32 	x1 = xc - xa; y1 = yc - ya;
33 	x2 = xc + xa; y2 = yc + ya;
34 	clip_ordbox(CURC,x1,y1,x2,y2);
35 	mouse_block(CURC,x1,y1,x2,y2);
36 	setup_ALLOC();
37 	if((xa == 0) || (ya == 0)) (*f->line)(
38 	    (x1 + CURC->gc_xoffset),
39 	    (y1 + CURC->gc_yoffset),
40 	    (x2 - x1),
41 	    (y2 - y1),
42 	    c
43 	);
44 	else if((xa > MAXR) || (ya > MAXR)) {   /* Bresenham would overflow !! */
45 	    int (*points)[2] = ALLOC(sizeof(int) * 2 * GR_MAX_ELLIPSE_POINTS);
46 	    if(points != NULL) {
47 		int count = GrGenerateEllipse(xc,yc,xa,ya,points);
48 		if(filled) _GrScanConvexPoly(count,points,f,c);
49 		else       _GrDrawPolygon(count,points,f,c,TRUE);
50 		FREE(points);
51 	    }
52 	}
53 	else {
54 	    int *scans = ALLOC(sizeof(int) * (ya + 1));
55 	    int  row   = ya;
56 	    int  col   = 0;
57 	    if(scans != NULL) {
58 		long yasq  = umul32(ya,ya);
59 		long xasq  = umul32(xa,xa);
60 		long xasq2 = xasq + xasq;
61 		long yasq2 = yasq + yasq;
62 		long xasq4 = xasq2 + xasq2;
63 		long yasq4 = yasq2 + yasq2;
64 		long error = (xasq2 * (row - 1) * row) +
65 			     (yasq2 * (1 - xasq))      +
66 			     xasq;
67 		while((xasq * row) > (yasq * col)) {
68 		    if(error >= 0) {
69 			scans[row] = col;
70 			row--;
71 			error -= xasq4 * row;
72 		    }
73 		    error += yasq2 * (3 + (col << 1));
74 		    col++;
75 		}
76 		error = (yasq2 * (col + 1) * col)         +
77 			(xasq2 * ((row * (row - 2)) + 1)) +
78 			(yasq  * (1 - xasq2));
79 		while(row >= 0) {
80 		    scans[row] = col;
81 		    if(error <= 0) {
82 			col++;
83 			error += yasq4 * col;
84 		    }
85 		    row--;
86 		    error += xasq2 * (2 - (row << 1));
87 		}
88 		for(row = y1; row <= y2; row++) {
89 		    col = iabs(yc - row);
90 		    if(!filled && (col < ya)) {
91 			x1 = xc - scans[col];
92 			x2 = xc - scans[col + 1];
93 			if(x1 < x2) x2--;
94 			do {
95 			    clip_ordxrange_(CURC,x1,x2,break,CLIP_EMPTY_MACRO_ARG);
96 			    (*f->scan)(
97 				(x1  + CURC->gc_xoffset),
98 				(row + CURC->gc_yoffset),
99 				(x2  - x1 + 1),
100 				c
101 			    );
102 			} while (0);
103 			x1 = xc + scans[col + 1];
104 			x2 = xc + scans[col];
105 			if(x1 < x2) x1++;
106 		    }
107 		    else {
108 			x1 = xc - scans[col];
109 			x2 = xc + scans[col];
110 		    }
111 			clip_ordxrange_(CURC,x1,x2,continue,CLIP_EMPTY_MACRO_ARG);
112 		    (*f->scan)(
113 			(x1  + CURC->gc_xoffset),
114 			(row + CURC->gc_yoffset),
115 			(x2  - x1 + 1),
116 			c
117 		    );
118 		}
119 		FREE(scans);
120 	    }
121 	}
122 	reset_ALLOC();
123 	mouse_unblock();
124 }
125 
126