## Friday, March 25, 2011

### How to draw a taichi image ?

We may draw a taichi by the following steps :
1. Draw 3 circles.
2. Erase the left half of the upper circle and the right half of the lower circle.
4. Fill regions with appropriate color.

### Straight forward implementation

```public void drawTaichi(BufferedImage image)
{
java.awt.Graphics2D gr = (java.awt.Graphics2D) image.getGraphics();
gr.setColor(java.awt.Color.WHITE);
gr.fillRect(0,0,300,300);

gr.setStroke(new java.awt.BasicStroke(2));  // pen width
gr.setColor(java.awt.Color.BLACK);

// draw a big circle with radius 100 with center at (150,150)
int xc=150, yc=150;  // center
// the bounding rectangle (x,y,w,h) of the circle is defined by :
// x=xc-r,  y=yc-r,  w=r*2,  h=r*2;
gr.drawArc(xc-r,yc-r,r*2,r*2,0,360);  // (x,y,w,h,startDegree,arcDegree)

// draw a small half circle with radius 50 with center at (150,100)
xc=150; yc=100; r=50;
gr.drawArc(xc-r,yc-r,r*2,r*2,270,180);  // (x,y,w,h,startDegree,arcDegree)

// draw another small half circle with radius 50 with center at (150,200)
xc=150; yc=200; r=50;
gr.drawArc(xc-r,yc-r,r*2,r*2,90,180);  // (x,y,w,h,startDegree,arcDegree)

// draw two more small circles ("eyes")
xc=150; yc=100; r=12;
gr.drawArc(xc-r,yc-r,r*2,r*2,0,360);  // (x,y,w,h,startDegree,arcDegree)

xc=150; yc=200; r=12;
gr.drawArc(xc-r,yc-r,r*2,r*2,0,360);  // (x,y,w,h,startDegree,arcDegree)

// fill with appropriate color
int black=packRgb(0,0,0);
floodFill(image,150,100,black);

floodFill(image,150,160,black);
}
```

The above implementation uses the floodFill() method described in the previous article.

### Improvement : removing the hard coded values

The above implementation is full of hard coded values such as 300,150,100...etc. A way to remove those hard coded values is to introduce magic constants such as :
```int BIG_RADIUS=100;
...
```

Another approach is to redefine the drawing routine to accept parameters. Full runnable sample follows :

```/******************************************************************************
* File : Taichi.java
* Author : http://java.macteki.com/
* Description :
*   Draw a Taichi image in a graphics panel.
* Tested with : JDK 1.6
******************************************************************************/

import java.awt.image.BufferedImage;
import java.awt.Point;

class Taichi extends javax.swing.JPanel
{
private BufferedImage taichiImage;

public static Taichi getInstance()
{
Taichi panel=new Taichi();
panel.setPreferredSize(new java.awt.Dimension(320,320));

panel.taichiImage = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);
panel.drawTaichi(panel.taichiImage,150,150,100);

return panel;
}

// draw a taichi image
public void drawTaichi(BufferedImage image,int xCenter,int yCenter, int radius)
{
java.awt.Graphics2D gr = (java.awt.Graphics2D) image.getGraphics();
gr.setColor(java.awt.Color.WHITE);
gr.fillRect(0,0,image.getWidth(this),image.getWidth(this));

gr.setStroke(new java.awt.BasicStroke(2));  // pen width
gr.setColor(java.awt.Color.BLACK);

// draw the big circle
int xc=xCenter, yc=yCenter;  // center
// the bounding rectangle (x,y,w,h) of the circle is defined by :
// x=xc-r,  y=yc-r,  w=r*2,  h=r*2;
gr.drawArc(xc-r,yc-r,r*2,r*2,0,360);  // (x,y,w,h,startDegree,arcDegree)

// draw a half circle inside the big circle
gr.drawArc(xc-r,yc-r,r*2,r*2,270,180);  // (x,y,w,h,startDegree,arcDegree)

// draw another half circle inside the big circle
gr.drawArc(xc-r,yc-r,r*2,r*2,90,180);  // (x,y,w,h,startDegree,arcDegree)

// draw two more small circles
gr.drawArc(xc-r,yc-r,r*2,r*2,0,360);  // (x,y,w,h,startDegree,arcDegree)

gr.drawArc(xc-r,yc-r,r*2,r*2,0,360);  // (x,y,w,h,startDegree,arcDegree)

// fill with appropriate color
int black=packRgb(0,0,0);

}

// override the paint method
// just paint the taichi image here
public void paintComponent(java.awt.Graphics graphics)
{
super.paintComponent(graphics);

// Graphics2D is a better choice to the default Graphics object
java.awt.Graphics2D gr=(java.awt.Graphics2D) graphics;

gr.drawImage(taichiImage,10,10,this);
}

public static int packRgb(int r,int g,int b)
{
return (r*256+g)*256+b;
}

// implements the flood fill algorithm
public static void floodFill(BufferedImage image, int x,int y, int fillColor)
{
java.util.ArrayList<Point> examList=new java.util.ArrayList<Point>();

int initialColor=image.getRGB(x,y);

while (examList.size()>0)
{
Point p = examList.remove(0);  // get and remove the first point in the list
if (image.getRGB(p.x,p.y)==initialColor)
{
x = p.x;  y = p.y;
image.setRGB(x, y, fillColor);  // fill current pixel

if (image.getRGB(x-1,y)==initialColor) // check west neighbor
{
}
if (image.getRGB(x+1,y)==initialColor) // check east neighbor
{
}
if (image.getRGB(x,y-1)==initialColor) // check north neighbor
{
}
if (image.getRGB(x,y+1)==initialColor) // check south neighbor
{
}

}
}

}

public static void main(String[] args) throws Exception
{
Taichi graphicPanel = Taichi.getInstance();

javax.swing.JFrame window=new javax.swing.JFrame();
window.pack();

window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
window.setTitle("Macteki Taichi Panel");
window.setVisible(true);
}
}
```

The next article will make a rotating Taichi animation.