lejos.internal.ev3.EV3GraphicsLCD Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lejos-ev3-api Show documentation
Show all versions of lejos-ev3-api Show documentation
leJOS (pronounced like the Spanish word "lejos" for "far") is a tiny Java Virtual Machine. In 2013 it was ported to the LEGO EV3 brick.
The newest version!
package lejos.internal.ev3;
import lejos.hardware.lcd.Font;
import lejos.hardware.lcd.GraphicsLCD;
import lejos.hardware.lcd.Image;
/**
* lcdui.graphics implementation for the EV3 LCD screen and in memory images.
* This class provides a sun-set of the standard JavaME graphics class. In
* particular it does not implement clipping. There are also several additional
* non-standard methods to allow easier use of images, alow access to inverse
* text, and allow the use of raster operations. Some of the standard limitations
* (like not allowing copyArea of the screen), are not enforced.
* @author Brian Bagnall and Andy
*
*/
public class EV3GraphicsLCD extends EV3LCD implements GraphicsLCD
{
/** drawArc and fillArc accuracy parameter */
private static final int ARC_ACC = 5;
private int rgbColor = BLACK;
private int textRop = ROP_OR;
private int pixelRop = ROP_SET;
private int strokeStyle = SOLID;
private Font font = Font.getDefaultFont();
private byte[] imageBuf;
private int width;
private int height;
private int transX = 0;
private int transY = 0;
/**
* Default constructor returns a context that can be used to access the NXT
* LCD display.
*/
public EV3GraphicsLCD(String layerName)
{
super(layerName);
imageBuf = getDisplay();
width = SCREEN_WIDTH;
height = SCREEN_HEIGHT;
}
/**
* Create a graphics object that can be used to access the supplied memory
* buffer.
* @param data The memory buffer
* @param width width of the buffer
* @param height height of the buffer
*/
public EV3GraphicsLCD(byte[] data, int width, int height)
{
imageBuf = data;
this.width = width;
this.height = height;
}
/**
* Adjust the x co-ordinate to use the translation and anchor values.
* @param x Original value
* @param w width of the item.
* @param anchor anchor parameter
* @return updated x value.
*/
private int adjustX(int x, int w, int anchor)
{
x += transX;
switch (anchor & (LEFT | RIGHT | HCENTER))
{
case LEFT:
break;
case RIGHT:
x -= w;
break;
case HCENTER:
x -= (w >> 1);
break;
}
return x;
}
/**
* Adjust the y co-ordinate to use the translation and anchor values.
* @param y Original value
* @param h height of the item.
* @param anchor anchor parameter
* @return updated y value.
*/
private int adjustY(int y, int h, int anchor)
{
y += transY;
switch (anchor & (TOP | BOTTOM | VCENTER))
{
case TOP:
break;
case BOTTOM:
y -= h;
break;
case VCENTER:
y -= (h >> 1);
break;
}
return y;
}
/* The following are non standard functions. What should we do with them */
/**
* Return the width of the associated drawing surface.
*
Note: This is a non standard method.
* @return width of the surface
*/
public int getWidth()
{
return width;
}
/**
* Return the height of the associated drawing surface.
*
Note: This is a non standard method.
* @return height of the surface.
*/
public int getHeight()
{
return height;
}
/**
* Draws the specified String using the current font and color. x and y
* give the location of the anchor point. Additional method to allow for
* the easy use of inverted text. In this case the area below the string
* is drawn in the current color, before drawing the text in the "inverted"
* color.
*
Note: This is a non standard method.
* @param str the String to be drawn
* @param x the x coordinate of the anchor point
* @param y the y coordinate of the anchor point
* @param anchor the anchor point for positioning the text
* @param inverted true to invert the text display.
*/
public void drawString(String str, int x, int y, int anchor, boolean inverted)
{
x += transX;
y += transY;
if (anchor == 0)
anchor = TOP | LEFT;
if ((anchor & LEFT) == 0)
{
int strWidth = font.stringWidth(str);
if ((anchor & RIGHT) != 0)
x -= strWidth;
else if ((anchor & HCENTER) != 0)
x -= (strWidth / 2);
}
if ((anchor & TOP) == 0)
{
if ((anchor & BASELINE) != 0)
y -= font.getBaselinePosition();
else if ((anchor & BOTTOM) != 0)
y -= font.getHeight();
}
int gw = font.glyphWidth;
int gh = font.height;
int rop = textRop;
int cellWidth = font.width;
byte[] glyphs = font.glyphs;
int span = gw * font.glyphCount;
int first = font.firstChar;
char[] strData = str.toCharArray();
if (inverted)
{
// draw background and use inverted rop...
bitBlt(null, width, height, 0, 0, imageBuf, width, height, x, y, cellWidth * strData.length, gh, pixelRop);
rop = (rgbColor == WHITE ? ROP_OR : ROP_ANDINVERTED);
}
for (int i = 0; i < strData.length; i++)
bitBlt(glyphs, span, gh, gw * (strData[i] - first), 0, imageBuf, width, height, x + i * cellWidth, y, gw, gh, rop);
}
/**
* Draw the specified image to the graphics surface, using the supplied rop.
*
Note: This is a non standard method.
* Added because without it, it is very
* hard to invert/manipulate an image, or screen region
* @param src image to draw (may be null for ops that do not require input.
* @param sx x offset in the source
* @param sy y offset in the source
* @param w width of area to draw
* @param h height of area to draw.
* @param x destination
* @param y destination
* @param anchor location of the anchor point
* @param rop drawing operation.
* @see Image
*/
public void drawRegionRop(Image src, int sx, int sy, int w, int h, int x, int y, int anchor, int rop)
{
x = adjustX(x, w, anchor);
y = adjustY(y, h, anchor);
if (src == null)
bitBlt(imageBuf, width, height, sx, sy, imageBuf, width, height, x, y, w, h, rop);
else
bitBlt(src.getData(), src.getWidth(), src.getHeight(), sx, sy, imageBuf, width, height, x, y, w, h, rop);
}
/**
* Draw the specified region of the source image to the graphics surface
* after applying the requested transformation, use the supplied rop.
*
NOTE: When calculating the anchor point this method assumes that
* a transformed version of the source width/height should be used.
* @param src The source image
* @param sx x coordinate of the region
* @param sy y coordinate of the region
* @param w width of the region
* @param h height of the region
* @param transform the required transform
* @param x x coordinate of the anchor point
* @param y y coordinate of the anchor point
* @param anchor type of anchor
* @param rop raster operation used to draw the output.
*/
public void drawRegionRop(Image src, int sx, int sy, int w, int h, int transform, int x, int y, int anchor, int rop)
{
// Check for common optimized case...
if (transform == 0)
{
drawRegionRop(src, sx, sy, w, h, x, y, anchor, rop);
return;
}
byte[] inData = src.getData();
int inWidth = src.getWidth();
int inHeight = src.getHeight();
// Transform matrix
int x1 = 1;
int y1 = 0;
int x2 = 0;
int y2 = 1;
// Transformed version of width/height.
int ow = w;
int oh = h;
switch (transform)
{
case TRANS_MIRROR:
x1 = -1;
break;
case TRANS_MIRROR_ROT180:
y2 = -1;
break;
case TRANS_MIRROR_ROT270:
x1 = 0;
y1 = 1;
x2 = 1;
y2 = 0;
ow = h;
oh = w;
break;
case TRANS_MIRROR_ROT90:
x1 = 0;
y1 = -1;
x2 = -1;
y2 = 0;
ow = h;
oh = w;
break;
case TRANS_ROT180:
x1 = -1;
y2 = -1;
break;
case TRANS_ROT270:
x1 = 0;
y1 = 1;
x2 = -1;
y2 = 0;
ow = h;
oh = w;
break;
case TRANS_ROT90:
x1 = 0;
y1 = -1;
x2 = 1;
y2 = 0;
ow = h;
oh = w;
break;
}
// Sort out the anchor point.
x = adjustX(x, ow, anchor);
y = adjustY(y, oh, anchor);
// perform the transformation.
// We rotate around the centre point
int cx = (w + 1) / 2;
int cy = (h + 1) / 2;
// Setup the input centre point
int sxbase = sx + cx;
int sybase = sy + cy;
// Setup the output centre point. Note that we use transformed rounding.
// If we don't do this the for even widths/heights we end up with a
// on symetric rotation.
int xbase = x + (ow + x1 + y1) / 2;
int ybase = y + (oh + x2 + y2) / 2;
// Now loop through the input region...
int iy = -cy;
int iye = iy + h;
while (iy < iye)
{
int iyy1 = iy * y1;
int iyy2 = iy * y2;
int ix = -cx;
int ixe = ix + w;
while (ix < ixe)
{
int ox = ix * x1 + iyy1 + xbase;
int oy = ix * x2 + iyy2 + ybase;
bitBlt(inData, inWidth, inHeight, sxbase + ix, sybase + iy, imageBuf, width, height, ox, oy, 1, 1, rop);
ix++;
}
iy++;
}
}
/**
* Clear the graphics surface to white.
*/
public void clear()
{
bitBlt(imageBuf, width, height, 0, 0, imageBuf, width, height, 0, 0, width, height, ROP_CLEAR);
}
/**
* Return the currently selected font object.
* @return Current font.
*/
public Font getFont()
{
return font;
}
public void setFont(Font f)
{
font = f;
}
/**
* Returns the actual color that will be used on the display if the specified
* color is requested. On the EV3 LCD and value that is not black will be
* treated as white.
* @param color
* @return the display color
*/
public int getDisplayColor(int color)
{
return color == BLACK ? BLACK : WHITE;
}
/**
* Set the current drawing color. The value is in the format 0x00RRGGBB.
* NOTE. Currently only black and white is supported. any non black color
* is treated as white!
* @param rgb new color.
*/
public void setColor(int rgb)
{
rgbColor = rgb;
if (rgbColor == BLACK)
{
pixelRop = ROP_SET;
textRop = ROP_OR;
}
else
{
pixelRop = ROP_CLEAR;
textRop = ROP_ANDINVERTED;
}
}
/**
* Sets the current color to the specified RGB values.
* @param red the red component
* @param green the green component
* @param blue the blue
* @throws IllegalArgumentException if any of the color components
* are outside of range 0-255
* @see #getColor
*/
public void setColor(int red, int green, int blue)
{
if ((red < 0) || (red > 255)
|| (green < 0) || (green > 255)
|| (blue < 0) || (blue > 255))
{
throw new IllegalArgumentException("bad color value");
}
setColor((red << 16) | (green << 8) | blue);
}
/**
* Return the current rgb color.
* @return current color.
*/
public int getColor()
{
return rgbColor;
}
/**
* Gets the red value of color.
* @return value in range 0-255
* @see #setColor(int, int, int)
*/
public int getRedComponent()
{
return (rgbColor >> 16) & 0xff;
}
/**
* Gets the green value of color.
* @return integer value in range 0-255
* @see #setColor(int, int, int)
*/
public int getGreenComponent()
{
return (rgbColor >> 8) & 0xff;
}
/**
* Gets the blue value of color.
* @return integer value in range 0-255
* @see #setColor(int, int, int)
*/
public synchronized int getBlueComponent()
{
return rgbColor & 0xff;
}
/**
* Draws the specified String using the current font and color. x and y
* give the location of the anchor point.
* @param str the String to be drawn
* @param x the x coordinate of the anchor point
* @param y the y coordinate of the anchor point
* @param anchor the anchor point for positioning the text
*/
public void drawString(String str, int x, int y, int anchor)
{
drawString(str, x, y, anchor, false);
}
/**
* Draw a substring to the graphics surface using the current color.
* @param str the base string
* @param offset the start of the sub string
* @param len the length of the sub string
* @param x the x coordinate of the anchor point
* @param y the x coordinate of the anchor point
* @param anchor the anchor point used to position the text.
*/
public void drawSubstring(String str, int offset, int len,
int x, int y, int anchor)
{
// will throw NullPointerException
int strLen = str.length();
if ((offset < 0) || (offset > strLen)
|| (len < 0) || (len > strLen)
|| ((offset + len) < 0) || ((offset + len) > strLen))
{
throw new StringIndexOutOfBoundsException();
}
drawString(str.substring(offset, offset + len), x, y, anchor);
}
/**
* Draw a single character to the graphics surface using the current color.
* @param character the character to draw
* @param x the x coordinate of the anchor point
* @param y the x coordinate of the anchor point
* @param anchor the anchor point used to position the text.
*/
public void drawChar(char character, int x, int y, int anchor)
{
drawString(new String(new char[]
{
character
}), x, y, anchor);
}
/**
* Draw a series of characters to the graphics surface using the current color.
* @param data the characters
* @param offset the start of the characters to be drawn
* @param length the length of the character string to draw
* @param x the x coordinate of the anchor point
* @param y the x coordinate of the anchor point
* @param anchor the anchor point used to position the text.
*/
public void drawChars(char[] data, int offset, int length,
int x, int y, int anchor)
{
// this will throw NullPointerException if data == null
int chLen = data.length;
if ((offset < 0) || (offset > chLen)
|| (length < 0) || (length > chLen)
|| ((offset + length) < 0) || ((offset + length) > chLen))
{
throw new ArrayIndexOutOfBoundsException();
}
drawString(new String(data, offset, length), x, y, anchor);
}
/**
* Draw the specified region of the supplied image to the graphics surface.
* NOTE: Transforms are not currently supported.
* @param src image to draw (may be null for ops that do not require input.
* @param sx x offset to the region
* @param sy y offset to the region
* @param w width of the region
* @param h height of the region
* @param transform
* @param x destination
* @param y destination
* @param anchor location of the anchor point
* @see Image
*/
public void drawRegion(Image src,
int sx, int sy,
int w, int h,
int transform,
int x, int y,
int anchor)
{
drawRegionRop(src, sx, sy, w, h, transform, x, y, anchor, ROP_COPY);
}
/**
* Draw the specified image to the graphics surface, using the supplied rop.
* @param src image to draw (may be null for ops that do not require input.
* @param x destination
* @param y destination
* @param anchor location of the anchor point
* @see Image
*/
public void drawImage(Image src, int x, int y, int anchor)
{
drawRegionRop(src, 0, 0, src.getWidth(), src.getHeight(), x, y, anchor, ROP_COPY);
}
/**
* Method to set a pixel to screen.
* @param x the x coordinate
* @param y the y coordinate
*/
private void setPixel(int x, int y)
{
bitBlt(imageBuf, width, height, 0, 0, imageBuf, width, height, x, y, 1, 1, pixelRop);
}
/**
* Draw a line between the specified points, using the current color and style.
* @param x0 x start point
* @param y0 y start point
* @param x1 x end point
* @param y1 y end point
*/
public void drawLine(int x0, int y0, int x1, int y1)
{
drawLine(x0, y0, x1, y1, strokeStyle);
}
private void drawLine(int x0, int y0, int x1, int y1, int style)
{
// Uses Bresenham's line algorithm
y0 += transY;
y1 += transY;
x0 += transX;
x1 += transX;
int dy = y1 - y0;
int dx = x1 - x0;
int stepx, stepy;
boolean skip = false;
if (style == SOLID && (dx == 0 || dy == 0))
{
// Special case horizontal and vertical lines
if (dx <= 0)
{
x0 = x1;
dx = -dx;
}
if (dy <= 0)
{
y0 = y1;
dy = -dy;
}
bitBlt(imageBuf, width, height, x0, y0, imageBuf, width, height, x0, y0,
dx + 1, dy + 1, (rgbColor == BLACK ? ROP_SET : ROP_CLEAR));
return;
}
if (dy < 0)
{
dy = -dy;
stepy = -1;
} else
{
stepy = 1;
}
if (dx < 0)
{
dx = -dx;
stepx = -1;
} else
{
stepx = 1;
}
dy <<= 1; // dy is now 2*dy
dx <<= 1; // dx is now 2*dx
setPixel(x0, y0);
if (dx > dy)
{
int fraction = dy - (dx >> 1); // same as 2*dy - dx
while (x0 != x1)
{
if (fraction >= 0)
{
y0 += stepy;
fraction -= dx; // same as fraction -= 2*dx
}
x0 += stepx;
fraction += dy; // same as fraction -= 2*dy
if ((style == SOLID) || !skip)
setPixel(x0, y0);
skip = !skip;
}
} else
{
int fraction = dx - (dy >> 1);
while (y0 != y1)
{
if (fraction >= 0)
{
x0 += stepx;
fraction -= dy;
}
y0 += stepy;
fraction += dx;
if ((style == SOLID) || !skip)
setPixel(x0, y0);
skip = !skip;
}
}
}
/**
* Draw an arc, using the current color and style.
* @param x
* @param y
* @param width
* @param height
* @param startAngle
* @param arcAngle
*/
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
{
drawArc(x, y, width, height, startAngle, arcAngle, strokeStyle, false);
}
/**
* Draw a filled arc, using the current color.
* @param x
* @param y
* @param width
* @param height
* @param startAngle
* @param arcAngle
*/
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
{
// drawArc is for now only SOLID
drawArc(x, y, width, height, startAngle, arcAngle, SOLID, true);
}
private void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle,
int style, boolean fill)
{
// Scale up width and height to create more accurate ellipse form
int xscale = (width < height) ? ARC_ACC : ((ARC_ACC * width + (width >> 1)) / height);
int yscale = (width < height) ? ((ARC_ACC * height + (height >> 1)) / width) : ARC_ACC;
x += transX;
y += transY;
// Calculate x, y center and radius from upper left corner
int x0 = x + (width >> 1);
int y0 = y + (height >> 1);
int radius = (width < height) ? (width >> 1) : (height >> 1);
if (arcAngle >= 360 || arcAngle <= -360)
{
drawTheCircle(radius, style, fill, xscale, yscale, x0, y0);
return;
}
while (startAngle < 0)
startAngle += 360;
while (startAngle > 360)
startAngle -= 360;
while (arcAngle > 360)
arcAngle -= 360;
while (arcAngle < -360)
arcAngle += 360; // negative arc angle is OK
// Check and set start and end angle
int endAngle = startAngle + arcAngle;
if (arcAngle >= 0)
{
if (endAngle > 360) // need 2 segments
{
drawTheArc(radius, style, fill, xscale, yscale, startAngle, 360, x0, y0);
drawTheArc(radius, style, fill, xscale, yscale, 0, endAngle - 360, x0, y0);
} else
drawTheArc(radius, style, fill, xscale, yscale, startAngle, endAngle, x0, y0);
} // else draw arc frem end to start
else if (endAngle < 0) // need 2 segments
{
drawTheArc(radius, style, fill, xscale, yscale, endAngle + 360, 360, x0, y0);
drawTheArc(radius, style, fill, xscale, yscale, 0, startAngle, x0, y0);
} else
drawTheArc(radius, style, fill, xscale, yscale, endAngle, startAngle, x0, y0);
}
private void drawTheCircle(int radius, int style, boolean fill, int xscale,
int yscale, int x0, int y0)
{
// Initialize scaled up Bresenham's circle algorithm
int f = (1 - ARC_ACC * radius);
int ddF_x = 0;
int ddF_y = -2 * ARC_ACC * radius;
int xc = 0;
int yc = ARC_ACC * radius;
int dotskip = 0;
while (xc < yc)
{
if (f >= 0)
{
yc--;
ddF_y += 2;
f += ddF_y;
}
xc++;
ddF_x += 2;
f += ddF_x + 1;
// Skip points for dotted version
dotskip = (dotskip + 1) % (2 * ARC_ACC);
if ((style == DOTTED) && !fill && (dotskip < ((2 * ARC_ACC) - 1)))
continue;
// Scale down again
int xxp = (xc * xscale + (xscale >> 1)) / (ARC_ACC * ARC_ACC);
int xyp = (xc * yscale + (yscale >> 1)) / (ARC_ACC * ARC_ACC);
int yyp = (yc * yscale + (yscale >> 1)) / (ARC_ACC * ARC_ACC);
int yxp = (yc * xscale + (xscale >> 1)) / (ARC_ACC * ARC_ACC);
if (fill)
{
/* TODO: Optimize more by drawing horizontal lines */
drawLine(x0, y0, x0 + yxp, y0 - xyp, style); // 0 - 45 degrees
drawLine(x0, y0, x0 + xxp, y0 - yyp, style); // 45 - 90 degrees
drawLine(x0, y0, x0 - xxp, y0 - yyp, style); // 90 - 135 degrees
drawLine(x0, y0, x0 - yxp, y0 - xyp, style); // 135 - 180 degrees
drawLine(x0, y0, x0 - yxp, y0 + xyp, style); // 180 - 225 degrees
drawLine(x0, y0, x0 - xxp, y0 + yyp, style); // 225 - 270 degrees
drawLine(x0, y0, x0 + xxp, y0 + yyp, style); // 270 - 315 degrees
drawLine(x0, y0, x0 + yxp, y0 + xyp, style); // 315 - 360 degrees
} else
{
setPixel(x0 + yxp, y0 - xyp); // 0 - 45 degrees
setPixel(x0 + xxp, y0 - yyp); // 45 - 90 degrees
setPixel(x0 - xxp, y0 - yyp); // 90 - 135 degrees
setPixel(x0 - yxp, y0 - xyp); // 135 - 180 degrees
setPixel(x0 - yxp, y0 + xyp); // 180 - 225 degrees
setPixel(x0 - xxp, y0 + yyp); // 225 - 270 degrees
setPixel(x0 + xxp, y0 + yyp); // 270 - 315 degrees
setPixel(x0 + yxp, y0 + xyp); // 315 - 360 degrees
}
}
}
private void drawTheArc(int radius, int style, boolean fill, int xscale,
int yscale, int startAngle, int endAngle, int x0, int y0)
{
// Initialize scaled up Bresenham's circle algorithm
int f = (1 - ARC_ACC * radius);
int ddF_x = 0;
int ddF_y = -2 * ARC_ACC * radius;
int xc = 0;
int yc = ARC_ACC * radius;
int dotskip = 0;
while (xc < yc)
{
if (f >= 0)
{
yc--;
ddF_y += 2;
f += ddF_y;
}
xc++;
ddF_x += 2;
f += ddF_x + 1;
// Skip points for dotted version
dotskip = (dotskip + 1) % (2 * ARC_ACC);
if ((style == DOTTED) && !fill && (dotskip < ((2 * ARC_ACC) - 1)))
continue;
// Scale down again
int xxp = (xc * xscale + (xscale >> 1)) / (ARC_ACC * ARC_ACC);
int xyp = (xc * yscale + (yscale >> 1)) / (ARC_ACC * ARC_ACC);
int yyp = (yc * yscale + (yscale >> 1)) / (ARC_ACC * ARC_ACC);
int yxp = (yc * xscale + (xscale >> 1)) / (ARC_ACC * ARC_ACC);
// Calculate angle for partly circles / ellipses
// NOTE: Below, (float) should not be needed. Not sure why Math.round() only accepts float.
int tp = (int) Math.round(Math.toDegrees(Math.atan2(yc, xc)));
if (fill)
{
/* TODO: Optimize more by drawing horizontal lines */
if (((90 - tp) >= startAngle) && ((90 - tp) <= endAngle))
drawLine(x0, y0, x0 + yxp, y0 - xyp, style); // 0 - 45 degrees
if ((tp >= startAngle) && (tp <= endAngle))
drawLine(x0, y0, x0 + xxp, y0 - yyp, style); // 45 - 90 degrees
if (((180 - tp) >= startAngle) && ((180 - tp) <= endAngle))
drawLine(x0, y0, x0 - xxp, y0 - yyp, style); // 90 - 135 degrees
if (((180 - (90 - tp)) >= startAngle) && ((180 - (90 - tp)) <= endAngle))
drawLine(x0, y0, x0 - yxp, y0 - xyp, style); // 135 - 180 degrees
if (((270 - tp) >= startAngle) && ((270 - tp) <= endAngle))
drawLine(x0, y0, x0 - yxp, y0 + xyp, style); // 180 - 225 degrees
if (((270 - (90 - tp)) >= startAngle) && ((270 - (90 - tp)) <= endAngle))
drawLine(x0, y0, x0 - xxp, y0 + yyp, style); // 225 - 270 degrees
if (((360 - tp) >= startAngle) && ((360 - tp) <= endAngle))
drawLine(x0, y0, x0 + xxp, y0 + yyp, style); // 270 - 315 degrees
if (((360 - (90 - tp)) >= startAngle) && ((360 - (90 - tp)) <= endAngle))
drawLine(x0, y0, x0 + yxp, y0 + xyp, style); // 315 - 360 degrees
} else
{
if (((90 - tp) >= startAngle) && ((90 - tp) <= endAngle))
setPixel(x0 + yxp, y0 - xyp); // 0 - 45 degrees
if ((tp >= startAngle) && (tp <= endAngle))
setPixel(x0 + xxp, y0 - yyp); // 45 - 90 degrees
if (((180 - tp) >= startAngle) && ((180 - tp) <= endAngle))
setPixel(x0 - xxp, y0 - yyp); // 90 - 135 degrees
if (((180 - (90 - tp)) >= startAngle) && ((180 - (90 - tp)) <= endAngle))
setPixel(x0 - yxp, y0 - xyp); // 135 - 180 degrees
if (((270 - tp) >= startAngle) && ((270 - tp) <= endAngle))
setPixel(x0 - yxp, y0 + xyp); // 180 - 225 degrees
if (((270 - (90 - tp)) >= startAngle) && ((270 - (90 - tp)) <= endAngle))
setPixel(x0 - xxp, y0 + yyp); // 225 - 270 degrees
if (((360 - tp) >= startAngle) && ((360 - tp) <= endAngle))
setPixel(x0 + xxp, y0 + yyp); // 270 - 315 degrees
if (((360 - (90 - tp)) >= startAngle) && ((360 - (90 - tp)) <= endAngle))
setPixel(x0 + yxp, y0 + xyp); // 315 - 360 degrees
}
}
}
/**
* Draw a rounded rectangle.
* @param x
* @param y
* @param width
* @param height
* @param arcWidth
* @param arcHeight
*/
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
{
x += transX;
y += transY;
int xc = x + (width / 2);
int yc = y + (height / 2);
int a = arcWidth / 2;
int b = arcHeight / 2;
int translateX = (width / 2) - (arcWidth / 2);
int translateY = (height / 2) - (arcHeight / 2);
// Draw 4 sides:
int xDiff = arcWidth / 2;
int yDiff = arcHeight / 2;
drawLine(x, y + yDiff, x, y + height - yDiff);
drawLine(x + width, y + yDiff, x + width, y + height - yDiff);
drawLine(x + xDiff, y, x + width - xDiff, y);
drawLine(x + xDiff, y + height, x + width - xDiff, y + height);
/* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
int xxx = 0, yyy = b;
int a2 = a * a, b2 = b * b;
int crit1 = -(a2 / 4 + a % 2 + b2);
int crit2 = -(b2 / 4 + b % 2 + a2);
int crit3 = -(b2 / 4 + b % 2);
int t = -a2 * yyy; /* e(xxx+1/2,y-1/2) - (a^2+b^2)/4 */
int dxt = 2 * b2 * xxx, dyt = -2 * a2 * yyy;
int d2xt = 2 * b2, d2yt = 2 * a2;
while (yyy >= 0 && xxx <= a)
{
setPixel(xc + xxx + translateX, yc + yyy + translateY); // Q4
if (xxx != 0 || yyy != 0)
setPixel(xc - xxx - translateX, yc - yyy - translateY); // Q2
if (xxx != 0 && yyy != 0)
{
setPixel(xc + xxx + translateX, yc - yyy - translateY); // Q1
setPixel(xc - xxx - translateX, yc + yyy + translateY); // Q3
}
if (t + b2 * xxx <= crit1
|| /* e(xxx+1,y-1/2) <= 0 */ t + a2 * yyy <= crit3) /* e(xxx+1/2,y) <= 0 */
{
xxx++;
dxt += d2xt;
t += dxt;
} // incx()
else if (t - a2 * yyy > crit2) /* e(xxx+1/2,y-1) > 0 */
{
yyy--;
dyt += d2yt;
t += dyt;
} else
{
{
xxx++;
dxt += d2xt;
t += dxt;
} // incx()
{
yyy--;
dyt += d2yt;
t += dyt;
}
}
}
}
/**
* Draw a rectangle using the current color and style.
* @param x
* @param y
* @param width
* @param height
*/
public void drawRect(int x, int y, int width, int height)
{
x += transX;
y += transY;
if ((width < 0) || (height < 0))
return;
if (height == 0 || width == 0)
{
drawLine(x, y, x + width, y + height);
} else
{
drawLine(x, y, x + width - 1, y);
drawLine(x + width, y, x + width, y + height - 1);
drawLine(x + width, y + height, x + 1, y + height);
drawLine(x, y + height, x, y + 1);
}
}
/**
* Draw a filled rectangle using the current color.
* @param x
* @param y
* @param w
* @param h
*/
public void fillRect(int x, int y, int w, int h)
{
x += transX;
y += transY;
if ((w < 0) || (h < 0))
return;
bitBlt(imageBuf, width, height, x, y, imageBuf, width, height, x, y, w, h, (rgbColor == BLACK ? ROP_SET : ROP_CLEAR));
}
/**
* Return the current stroke style.
* @return current style.
*/
public int getStrokeStyle()
{
return strokeStyle;
}
/**
* Set the stroke style to be used for drawing operations.
* @param style new style.
*/
public void setStrokeStyle(int style)
{
if (style != SOLID && style != DOTTED)
{
throw new IllegalArgumentException();
}
strokeStyle = style;
}
/**
* Copy one rectangular area of the drawing surface to another.
* @param sx Source x
* @param sy Source y
* @param w Source width
* @param h Source height
* @param x Destination x
* @param y Destination y
* @param anchor location of the anchor point of the destination.
*/
public void copyArea(int sx, int sy,
int w, int h,
int x, int y, int anchor)
{
x = adjustX(x, w, anchor);
y = adjustY(y, h, anchor);
bitBlt(imageBuf, width, height, sx, sy, imageBuf, width, height, x, y, w, h, ROP_COPY);
}
/**
* Translates the origin of the graphics context to the point
* (x, y) in the current coordinate system. Calls are cumulative.
*
* @param x the new translation origin x value
* @param y new translation origin y value
* @see #getTranslateX()
* @see #getTranslateY()
*/
public synchronized void translate(int x, int y)
{
transX += x;
transY += y;
}
/**
* Gets the X coordinate of the translated origin of this graphics context.
* @return X of current origin
*/
public synchronized int getTranslateX()
{
return transX;
}
/**
* Gets the Y coordinate of the translated origin of this graphics context.
* @return Y of current origin
*/
public synchronized int getTranslateY()
{
return transY;
}
}