import javax.swing.*;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;

public class CharacterImage extends JPanel  {
    AffineTransform transform;
    public CharacterImage() {
        setBackground(Color.white);
	transform = new AffineTransform();
	transform.translate(0, 150);
	transform.scale(75, -75);
    }    

    public void paintComponent(Graphics gfx) {
        super.paintComponent(gfx);
        Graphics2D g = (Graphics2D) gfx;
	g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
			   RenderingHints.VALUE_ANTIALIAS_ON);

	String string = "g";
	Font font = new Font("serif", Font.PLAIN, 2);
	g.setFont(font);
	FontRenderContext frc = g.getFontRenderContext();
	GlyphVector glyphVector = font.createGlyphVector(frc, string);

	Shape shape = glyphVector.getGlyphOutline(0, 0.11f, 0.8f);
	shape = 
	    AffineTransform.getScaleInstance(1, -1).createTransformedShape(shape);

	g.setPaint(new Color(0.8f, 0.8f, 0.8f));
	for (int i = 0; i <= 4; i++) {
	    Line2D.Double line = new Line2D.Double(i, -2, i, 2);
	    g.draw(transform.createTransformedShape(line));
	}
	for (int i = -2; i <= 2; i++) {
	    Line2D.Double line = new Line2D.Double(0, i, 4, i);
	    g.draw(transform.createTransformedShape(line));
	}
	g.setPaint(Color.black);
	Line2D.Double line = new Line2D.Double(0, -2, 0, 2);
	g.draw(transform.createTransformedShape(line));
	line = new Line2D.Double(0, 0, 4, 0);
	g.draw(transform.createTransformedShape(line));

	g.setPaint(Color.gray);
	Arc2D.Double arc = new Arc2D.Double(-1, -1, 2, 2, -90, 180, Arc2D.OPEN);
	g.draw(transform.createTransformedShape(arc));

	g.setPaint(Color.blue);
	g.draw(transform.createTransformedShape(shape));
	FlatteningPathIterator iterator =
	    new FlatteningPathIterator(shape.getPathIterator(null), 0.01);
				       
	double[] begin = new double[2];
	double[] last  = new double[2];

	g.setPaint(Color.red);
	while(!iterator.isDone()) {
	    float[] coords = new float[6];
	    int type = iterator.currentSegment(coords);
	    switch(type) {
	    case(PathIterator.SEG_MOVETO): {
		begin = new double[] {coords[0], coords[1]};
		last  = begin;
		break;
	    }
	    case(PathIterator.SEG_LINETO): {
		double[] next = new double[] {coords[0], coords[1]};
		drawLine(last, next, g);
		last = next;
		break;
	    }
	    case(PathIterator.SEG_QUADTO): {
		System.out.println("Quadratic Curve!");
		break;
	    }
	    case(PathIterator.SEG_CUBICTO): {
		System.out.println("Cubic Curve!");
		break;
	    }
	    case(PathIterator.SEG_CLOSE): {
		drawLine(last, begin, g);
		break;
	    }
	    }
	    iterator.next();
	}

    }

    public void drawLine(double[] p0, double[] p1, Graphics2D g) {
	double dx = (p1[0] - p0[0])/100;    // not so elegant
	double dy = (p1[1] - p0[1])/100;
	double lastX = p0[0];  double lastY = p0[1];
	for (int i = 1; i <= 100; i++) {
	    double nextX = p0[0] + i*dx;
	    double nextY = p0[1] + i*dy;
	    double[] f0 = f(lastX, lastY);
	    double[] f1 = f(nextX, nextY);
	    lastX = nextX;  lastY = nextY;
	    Line2D.Double line = new Line2D.Double(f0[0], f0[1], f1[0], f1[1]);
	    g.draw(transform.createTransformedShape(line));
	}
	    
    }

    public double[] f(double x, double y) {
	double l = x*x + y*y;
	double[] r = new double[2];
	r[0] = x/l; r[1] = -y/l;
	return r;
    }

    public static void main(String[] args) {
        JPEGDrawFrame frame = new JPEGDrawFrame("CharacterImage");
        CharacterImage image = new CharacterImage();
        frame.getContentPane().add(image, BorderLayout.CENTER);
        image.setPreferredSize(new Dimension(301, 301));
        frame.pack();
        frame.show();
    }
}
