import java.awt.*;

public class Transpose3d {
	double		scale = 1.2;
	double		phi = 0.0;
	double		lambda = Math.PI / 6.0;

	public void rotate(double dPhi) { phi += dPhi; }

	public void drawScale(Graphics g) {
		Point	lower, upper, tick;

		lower = mapPoint(g, -1.0, 0.0, 0.0);
		upper = mapPoint(g, 1.0, 0.0, 0.0);
		g.drawLine(lower.x, lower.y, upper.x, upper.y);
		tick = mapPoint(g, 1.0, 0.07, 0.0);
		g.drawLine(upper.x, upper.y, tick.x, tick.y);
		tick = mapPoint(g, 1.0, 0.15, 0.0);
		g.drawString("x", tick.x, tick.y);

		lower = mapPoint(g, 0.0, -1.0, 0.0);
		upper = mapPoint(g, 0.0, 1.0, 0.0);
		g.drawLine(lower.x, lower.y, upper.x, upper.y);
		tick = mapPoint(g, 0.07, 1.0, 0.0);
		g.drawLine(upper.x, upper.y, tick.x, tick.y);
		tick = mapPoint(g, 0.15, 1.0, 0.0);
		g.drawString("y", tick.x, tick.y);

		lower = mapPoint(g, 0.0, 0.0, -1.0);
		upper = mapPoint(g, 0.0, 0.0,  1.0);
		g.drawLine(lower.x, lower.y, upper.x, upper.y);
	}

	public void drawHVA(Graphics g, HVector hva[], double vscale) {
		final int ovalRadius = 2;
		int points = hva.length;
		int xs[] = new int[points];
		int ys[] = new int[points];
		for (int i = 0; i < points; i++) {
			HVector hv = hva[i];
			double z = -(double)i * vscale / (double)hva.length;
			Point p = mapPoint(g, hv.x, hv.y, z);
			xs[i] = p.x;
			ys[i] = p.y;
			g.drawOval(p.x - ovalRadius, p.y - ovalRadius,
				ovalRadius * 2, ovalRadius * 2);
		}
		g.drawPolyline(xs, ys, points);
	}

	public Point mapPoint(Graphics g, double x, double y, double z) {
		Rectangle r = g.getClipBounds();
		// horizontal rotation by (phi)
		double x2 = x * Math.cos(phi) + y * Math.sin(phi);
		double y2 = -x * Math.sin(phi) + y * Math.cos(phi);
		// vertical rotation by (lambda)
		double x3 = y2;
		double y3 = -(z * Math.cos(lambda) - x2 * Math.sin(lambda));
		int width = (r.width > r.height) ? r.height : r.width; 
		return new Point(scale(r.x, width, x3),
			scale(r.y + r.height - width, width, y3));
	}

	public int scale(int lower, int width, double x) {
		return lower + (width + (int)(x / scale * width)) / 2;
	}
}
