package javax.microedition.lcdui;
import lejos.nxt.LCD;
/**
* Preliminary Graphics class for LCD Screen
* @author Brian Bagnall
*
*/
public class Graphics
{
/** drawArc and fillArc accuracy parameter */
private static final int ARC_ACC = 5;
/* Public color definitions */
public static final int BLACK = 1;
public static final int WHITE = 0;
/* Public line stroke definitions */
public static final int SOLID = 0;
public static final int DOTTED = 2;
private int rgbColor = BLACK;
private int strokeStyle = SOLID;
private Font font = new Font();
public Graphics()
{
}
public int getWidth()
{
return LCD.SCREEN_WIDTH;
}
public int getHeight()
{
return LCD.SCREEN_HEIGHT;
}
public int getCenteredX(String str)
{
return (LCD.DISPLAY_CHAR_WIDTH - str.length()) * LCD.CELL_WIDTH / 2;
}
public Font getFont()
{
return font;
}
public void setColor(int rgb)
{
rgbColor = rgb;
}
public int getColor()
{
return rgbColor;
}
/**
* Using rgbColor as argument even though global, because when this
* setPixel() method is used later it will need color argument
*/
public void setPixel(int rgbColor, int x, int y)
{
LCD.setPixel(rgbColor, x, y);
}
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
int dy = y1 - y0;
int dx = x1 - x0;
int stepx, stepy;
boolean skip = false;
if (dy < 0)
{
dy = -dy;
stepy = -1;
} else
{
stepy = 1;
}
if (dx < 0)
{
dx = -dx;
stepx = -1;
} else
{
stepx = 1;
}
if (style == SOLID)
{
// Special case horizontal and vertical lines
if (dy == 0 || dx == 0)
{
LCD.bitBlt((stepx == 1 ? x0 : x1), (stepy == 1 ? y0 : y1),
(dx == 0 ? 1 : dx + 1), (dy == 0 ? 1 : dy + 1), (rgbColor == BLACK ? LCD.ROP_SET : LCD.ROP_CLEAR));
return;
}
}
dy <<= 1; // dy is now 2*dy
dx <<= 1; // dx is now 2*dx
setPixel(rgbColor, 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(rgbColor, 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(rgbColor, x0, y0);
skip = !skip;
}
}
}
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
{
drawArc(x, y, width, height, startAngle, arcAngle, strokeStyle, false);
}
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;
// 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);
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;
// while (endAngle < 0)
// {
// endAngle = endAngle + 360;
// }
// while (endAngle > 360)
// {
// endAngle = endAngle - 360;
// }
// if (arcAngle < 0)
// { // Switches start and end
// int temp = startAngle;
// startAngle = endAngle;
// endAngle = (temp > 0) ? temp : temp + 360; // was just :temp
// }
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 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(rgbColor, x0 + yxp, y0 - xyp); // 0 - 45 degrees
if ((tp >= startAngle) && (tp <= endAngle))
setPixel(rgbColor, x0 + xxp, y0 - yyp); // 45 - 90 degrees
if (((180 - tp) >= startAngle) && ((180 - tp) <= endAngle))
setPixel(rgbColor, x0 - xxp, y0 - yyp); // 90 - 135 degrees
if (((180 - (90 - tp)) >= startAngle) && ((180 - (90 - tp)) <= endAngle))
setPixel(rgbColor, x0 - yxp, y0 - xyp); // 135 - 180 degrees
if (((270 - tp) >= startAngle) && ((270 - tp) <= endAngle))
setPixel(rgbColor, x0 - yxp, y0 + xyp); // 180 - 225 degrees
if (((270 - (90 - tp)) >= startAngle) && ((270 - (90 - tp)) <= endAngle))
setPixel(rgbColor, x0 - xxp, y0 + yyp); // 225 - 270 degrees
if (((360 - tp) >= startAngle) && ((360 - tp) <= endAngle))
setPixel(rgbColor, x0 + xxp, y0 + yyp); // 270 - 315 degrees
if (((360 - (90 - tp)) >= startAngle) && ((360 - (90 - tp)) <= endAngle))
setPixel(rgbColor, x0 + yxp, y0 + xyp); // 315 - 360 degrees
}
}
}
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
{
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, height - yDiff);
drawLine(width, y + yDiff, width, height - yDiff);
drawLine(x + xDiff, y, width - xDiff, y);
drawLine(x + xDiff, height, width - xDiff, 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(BLACK, xc + xxx + translateX, yc + yyy + translateY); // Q4
if (xxx != 0 || yyy != 0)
setPixel(BLACK, xc - xxx - translateX, yc - yyy - translateY); // Q2
if (xxx != 0 && yyy != 0)
{
setPixel(BLACK, xc + xxx + translateX, yc - yyy - translateY); // Q1
setPixel(BLACK, 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;
}
}
}
}
public void drawRect(int x, int y, int width, int height)
{
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);
}
}
public void fillRect(int x, int y, int width, int height)
{
if ((width < 0) || (height < 0))
return;
LCD.bitBlt(x, y, width, height, (rgbColor == BLACK ? LCD.ROP_SET : LCD.ROP_CLEAR));
}
public void drawString(String str, int x, int y, int rop)
{
LCD.drawString(str, x, y, rop);
}
public void drawString(String str, int x, int y)
{
drawString(str, x, y, LCD.ROP_COPY);
}
public void drawString(String str, int x, int y, boolean invert)
{
LCD.drawString(str, x, y, invert);
}
public void drawChar(char c, int x, int y, boolean invert)
{
LCD.drawChar(c, x, y, invert);
}
public void drawImage(Image img, int x, int y, boolean invert)
{
if (img == null)
{
return;
}
LCD.bitBlt(img.getData(), img.getWidth(), img.getHeight(), 0, 0, x, y, img.getWidth(), img.getHeight(), (invert ? LCD.ROP_COPYINVERTED : LCD.ROP_COPY));
}
public void drawImage(Image img, int sx, int sy, int x, int y, int w, int h, int rop)
{
if (img == null)
LCD.bitBlt(x, y, w, h, rop);
else
LCD.bitBlt(img.getData(), img.getWidth(), img.getHeight(), sx, sy, x, y, w, h, rop);
}
public int getStrokeStyle()
{
return strokeStyle;
}
public void setStrokeStyle(int style)
{
if (style != SOLID && style != DOTTED)
{
throw new IllegalArgumentException();
}
strokeStyle = style;
}
// Temp for testing purposes until Canvas made.
public void refresh()
{
LCD.setDisplay();
LCD.refresh();
}
// Temp method for testing. Clears out graphics buffer
// and refreshes screen.
public void clear()
{
LCD.clearDisplay();
}
public void autoRefresh(boolean on)
{
LCD.setAutoRefresh((on ? 1 : 0));
}
}
/*
class LCD extends JPanel {
public static final int SCREEN_WIDTH = 100;
public static final int SCREEN_HEIGHT = 64;
public static final int SCREEN_SCALE = 4;
public static int [] screenBuf;
public Graphics nxjGraphics;
// drawArc and fillArc parameters
int x = 10;
int y = 10;
int width = 80;
int height = 50;
int start = 0;
int angle = -135;
public LCD() {
setBackground(Color.WHITE);
setPreferredSize(new Dimension(SCREEN_SCALE * SCREEN_WIDTH,
SCREEN_SCALE * SCREEN_HEIGHT));
nxjGraphics = new Graphics();
nxjGraphics.setStrokeStyle(Graphics.DOTTED);
nxjGraphics.drawLine(0, 0, 100, 64);
nxjGraphics.fillArc(x, y, width, height, start, angle);
nxjGraphics.drawArc(10, 10, 20, 40, 0, 360);
// nxjGraphics.drawRoundRect(75, 5, 20, 10, 45, 45);
nxjGraphics.refresh();
repaint();
}
public static void drawString(String str, int x, int y) {}
public static void setDisplay(int [] buff) {
screenBuf = buff;
}
public static void refresh() {}
public synchronized void paint(java.awt.Graphics g) {
int w = getSize().width;
int h = getSize().height;
java.awt.Graphics2D g2 = (java.awt.Graphics2D) g;
g2.setBackground(getBackground());
g2.clearRect(0, 0, w, h);
// Draw example image for verification
g2.setColor(Color.RED);
g2.fillArc(SCREEN_SCALE * x, SCREEN_SCALE * y, SCREEN_SCALE * width,
SCREEN_SCALE * height, start, angle);
g2.drawRect(300, 20, 80, 40);
g2.drawRoundRect(300, 20, 80, 40, 45, 30);
// Draw NXJ image
g2.setColor(Color.BLACK);
for (int xp = 0; xp < 100; xp++) {
for (int yp = 0; yp < 64; yp++) {
if (xp < 0 || xp >= 100 || yp < 0 || yp >= 64) continue;
int xChar = xp / 4;
int yChar = yp / 8;
int index = yChar * 25 + xChar;
int specificBit = (yp % 8) + ((xp % 4) * 8);
if ((screenBuf[index] & (1 << specificBit)) != 0) {
g2.drawRect(SCREEN_SCALE * xp, SCREEN_SCALE * yp,
SCREEN_SCALE, SCREEN_SCALE);
}
}
}
}
}
class TestApp extends JFrame {
public TestApp() {
// End application when window is closed
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setTitle("NXJ Grapics test app");
getContentPane().add(new LCD());
pack();
show();
}
public static void main(String[] args) {
new TestApp();
}
}
*/