?? draw-arc.c
字號:
/*
* ARC Drawing API
*
*
* COPYRIGHT (c) 2001 - 2010.
* emTech System Corporation.
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE.
*/
/* Huangf emcore@263.net
*/
/* Stolen from microwindows
*/
#include "emGUI.h"
/* argument holder for pie, arc and ellipse functions*/
typedef struct {
WndID wID;
GID gID;
int x0, y0;
int rx, ry;
int ax, ay;
int bx, by;
int adir, bdir;
int type;
} SLICE;
/*
* Clip a line segment for arc or pie drawing.
* Returns 0 if line is clipped or on acceptable side, 1 if it's vertically
* on other side, otherwise 3.
*/
static int
clip_line(
SLICE *slice,
int xe,
int ye,
int dir,
int y,
int *x0,
int *x1
)
{
/* hline on the same vertical side with the given edge? */
if ((y >= 0 && ye >= 0) || (y < 0 && ye < 0)) {
int x;
if (ye == 0) x = xe; else
x = (int)(long)xe * y / ye;
if (x >= *x0 && x <= *x1) {
if (dir > 0)
*x0 = x;
else
*x1 = x;
return 0;
} else {
if (dir > 0) {
if (x <= *x0)
return 0;
} else {
if (x >= *x1)
return 0;
}
}
return 3;
}
return 1;
}
/* relative offsets, direction from left to right. */
static void
draw_line(
SLICE *slice,
int x0,
int y,
int x1
)
{
int dbl = (slice->adir > 0 && slice->bdir < 0);
int discard, ret;
int x2 = x0, x3 = x1;
if (y == 0) {
if (slice->type != GRPIE)
return;
/* edges on different sides */
if ((slice->ay <= 0 && slice->by >= 0) ||
(slice->ay >= 0 && slice->by <= 0)) {
if (slice->adir < 0) {
if (x1 > 0)
x1 = 0;
}
if (slice->bdir > 0) {
if (x0 < 0)
x0 = 0;
}
} else {
if (!dbl) {
/* FIXME leaving in draws dot in center*/
GrPoint(slice->wID, slice->gID, slice->x0, slice->y0);
return;
}
}
GrLine(slice->wID, slice->gID, slice->x0 + x0, slice->y0, slice->x0 + x1, slice->y0, TRUE);
return;
}
/* clip left edge / line */
ret = clip_line(slice, slice->ax, slice->ay, slice->adir, y, &x0, &x1);
if (dbl) {
if (!ret) {
/* edges separate line to two parts */
GrLine(
slice->wID,
slice->gID,
slice->x0 + x0,
slice->y0 + y,
slice->x0 + x1,
slice->y0 + y,
TRUE
);
x0 = x2;
x1 = x3;
}
}
else {
if (ret > 1) {
return;
}
}
discard = ret;
ret = clip_line(slice, slice->bx, slice->by, slice->bdir, y, &x0, &x1);
discard += ret;
if (discard > 2 && !(dbl && ret == 0 && discard == 3)) {
return;
}
if (discard == 2) {
/* line on other side than slice */
if (slice->adir < 0 || slice->bdir > 0) {
return;
}
}
GrLine(
slice->wID,
slice->gID,
slice->x0 + x0,
slice->y0 + y,
slice->x0 + x1,
slice->y0 + y,
TRUE
);
}
/* draw one line segment or set of points, called from drawarc routine*/
static void
drawarcsegment(SLICE *slice, int xp, int yp)
{
switch (slice->type & 0x0f) {
case GRELLIPSEFILL:
/* draw ellipse fill segment*/
GrLine(
slice->wID,
slice->gID,
slice->x0 - xp,
slice->y0 - yp,
slice->x0 + xp,
slice->y0 - yp,
TRUE
);
GrLine(
slice->wID,
slice->gID,
slice->x0 - xp,
slice->y0 + yp,
slice->x0 + xp,
slice->y0 + yp,
TRUE
);
return;
case GRELLIPSE:
/* set four points symmetrically situated around a point*/
GrPoint(
slice->wID,
slice->gID,
slice->x0 + xp,
slice->y0 + yp
);
GrPoint(
slice->wID,
slice->gID,
slice->x0 - xp,
slice->y0 + yp
);
GrPoint(
slice->wID,
slice->gID,
slice->x0 + xp,
slice->y0 - yp
);
GrPoint(
slice->wID,
slice->gID,
slice->x0 - xp,
slice->y0 - yp
);
return;
case GRPIE:
/* draw top and bottom halfs of pie*/
if (slice->type & GRLEFTTOP){
draw_line(slice, -xp, -yp, 0);
}
if (slice->type & GRRIGHTTOP){
draw_line(slice, 0, -yp, +xp);
}
if (slice->type & GRLEFTBOTTOM){
draw_line(slice, -xp, +yp, 0);
}
if (slice->type & GRRIGHTBOTTOM){
draw_line(slice, 0, +yp, +xp);
}
return;
default: /* GRARC, GRARCOUTLINE*/
/* set four points symmetrically around a point and clip*/
if (slice->type & GRRIGHTBOTTOM){
draw_line(slice, +xp, +yp, +xp);
}
if (slice->type & GRLEFTBOTTOM){
draw_line(slice, -xp, +yp, -xp);
}
if (slice->type & GRRIGHTTOP){
draw_line(slice, +xp, -yp, +xp);
}
if (slice->type & GRLEFTTOP){
draw_line(slice, -xp, -yp, -xp);
}
return;
}
}
/* General routine to plot points on an arc. Used by arc, pie and ellipse*/
static void
drawarc(SLICE *slice)
{
int xp, yp; /* current point (based on center) */
int rx, ry;
long Asquared; /* square of x semi axis */
long TwoAsquared;
long Bsquared; /* square of y semi axis */
long TwoBsquared;
long d;
long dx, dy;
rx = slice->rx;
ry = slice->ry;
xp = 0;
yp = ry;
Asquared = rx * rx;
TwoAsquared = 2 * Asquared;
Bsquared = ry * ry;
TwoBsquared = 2 * Bsquared;
d = Bsquared - Asquared * ry + (Asquared >> 2);
dx = 0;
dy = TwoAsquared * ry;
while (dx < dy) {
drawarcsegment(slice, xp, yp);
if (d > 0) {
yp--;
dy -= TwoAsquared;
d -= dy;
}
xp++;
dx += TwoBsquared;
d += (Bsquared + dx);
}
d += ((3L * (Asquared - Bsquared) / 2L - (dx + dy)) >> 1);
while (yp >= 0) {
drawarcsegment(slice, xp, yp);
if (d < 0) {
xp++;
dx += TwoBsquared;
d += dx;
}
yp--;
dy -= TwoAsquared;
d += (Asquared - dy);
}
}
/*
* Draw an arc or pie using start/end points.
* Integer only routine. To specify start/end angles,
* use GdArcAngle, which requires floating point.
*/
void
GrArc(
WndID wID,
GID gID,
int x0,
int y0,
int rx,
int ry,
int ax,
int ay,
int bx,
int by,
int type
)
{
int adir, bdir;
SLICE slice;
if (rx <= 0 || ry <= 0)
return;
/*
* Calculate right/left side clipping, based on quadrant.
* dir is positive when right side is filled and negative when
* left side is to be filled.
*
* >= 0 is bottom half
*/
if (ay >= 0)
adir = 1;
else
adir = -1;
if (by >= 0)
bdir = -1;
else
bdir = 1;
/*
* The clip_line routine has problems around the 0 and
* 180 degree axes.
* This <fix> is required to make the clip_line algorithm
* work. Getting these routines to work for all angles is
* a bitch. And they're still buggy. Doing this causes
* half circles to be outlined with a slightly bent line
* on the x axis. FIXME
*/
if (ay == 0) ++ay;
if (by == 0) ++by;
/* swap rightmost edge first */
if (bx > ax) {
int swap;
swap = ax;
ax = bx;
bx = swap;
swap = ay;
ay = by;
by = swap;
swap = adir;
adir = bdir;
bdir = swap;
}
slice.wID = wID;
slice.gID = gID;
slice.x0 = x0;
slice.y0 = y0;
slice.rx = rx;
slice.ry = ry;
slice.ax = ax;
slice.ay = ay;
slice.bx = bx;
slice.by = by;
slice.adir = adir;
slice.bdir = bdir;
slice.type = type;
drawarc(&slice);
if (type & GROUTLINE) {
/* draw two lines from rx,ry to arc endpoints*/
GrLine(wID, gID, x0, y0, x0+ax, y0+ay, TRUE);
GrLine(wID, gID, x0, y0, x0+bx, y0+by, TRUE);
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -