package jmathlib.core.graphics.axes;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import jmathlib.core.interpreter.ErrorLogger;
import jmathlib.core.graphics.*;
import jmathlib.core.graphics.Matrix3D;
import jmathlib.core.graphics.properties.*;
import jmathlib.core.graphics.axes.coreObjects.*;
/** created and holds the axes of a plot*/
public class Axes3DObject extends AxesObject implements MouseListener, MouseMotionListener
{
boolean painted = true;
boolean boxVisible = false;
double xfac;
double prevx, prevy;
double xtheta = 120;
double ztheta = 60;
double scalefudge = 1;
Matrix3D rotMat = new Matrix3D();
Matrix3D mat = new Matrix3D(); //?
String mdname = null; /**??*/
public Axes3DObject()
{
super();
rotMat = makeRotMatrix();
component.addMouseListener(this);
component.addMouseMotionListener(this);
XGridP.set(true);
YGridP.set(true);
ZGridP.set(true);
}
private Matrix3D makeRotMatrix()
{
Matrix3D mat = new Matrix3D();
mat.unit();
mat.zrot(ztheta);
mat.xrot(xtheta);
return mat;
}
/** add a line to the current plot */
public void add3DLine(double[] _x, double[] _y, double[] _z)
{
ErrorLogger.debugLine("Axes3DObject: add3DLine");
// if this plot is not on hold. Remove all Elements before plotting
if (NextPlotP.is("replace"))
ChildrenP.removeAllElements();
// add line to plot
ChildrenP.addElement(new Line3DObject(_x, _y, _z));
autoScale();
}
/** add lines to the current plot */
public void add3DLines(double[][] _x, double[][] _y, double[][] _z, String color, String lineStyle, String marker)
{
ErrorLogger.debugLine("Axes3DObject: add3DLines");
// if this plot is not on hold. Remove all Elements before plotting
if (NextPlotP.is("replace"))
ChildrenP.removeAllElements();
// add lines to plot
for (int n=0; n<_y.length; n++)
{
ChildrenP.addElement(new Line3DObject(_x[n], _y[n], _z[n], color, lineStyle, marker));
}
autoScale();
}
/** add a surface to the current axes */
public void addSurface(double[][] _x, double[][] _y, double[][] _z)
{
//ErrorLogger.debugLine("Axes3DObject: addSurface");
// if this plot is not on hold. Remove all Elements before plotting
if (NextPlotP.is("replace"))
ChildrenP.removeAllElements();
// add surface to plot
ChildrenP.addElement(new SurfaceObject(_x, _y, _z, 'b', ' ', ' '));
autoScale();
}
public void paint(Graphics _g)
{
Graphics g = initBackBuffer(_g);
//ErrorLogger.debugLine("Axes3DObject: paint");
//System.out.println("width = "+this.getSize().width+" height = "+this.getSize().height);
dyFrame = this.getSize().height;
dxFrame = this.getSize().width;
// if these axes hold no data -> do nothing
if (ChildrenP.size() == 0) return;
// size of curves
int dyCurves = (int)(dyFrame*3/4);
int dxCurves = (int)(dxFrame*3/4);
// Origin of curves
int dyOrig = (dyFrame-dyCurves)/2;
int dxOrig = (dxFrame-dxCurves)/2;
FontMetrics fM = g.getFontMetrics();
int sAscent = fM.getAscent();
int sDescent = fM.getDescent();
// Find range of x-axis, y-axis and z-axis
double xmin, xmax, ymin, ymax, zmin, zmax, dx, dy, dz;
// X axis
xmin = XLimP.getArray()[0];
xmax = XLimP.getArray()[1];
dx = xmax-xmin;
// Y axis
ymin = YLimP.getArray()[0];
ymax = YLimP.getArray()[1];
dy = ymax-ymin;
// Z axis
zmin = ZLimP.getArray()[0];
zmax = ZLimP.getArray()[1];
dz = zmax-zmin;
g.setColor(Color.black);
mat.unit();
mat.translate(-0.5, -0.5, -0.5);
mat.mult(rotMat);
double f1 = Math.abs(Math.cos(ztheta*Math.PI/180.0f))+Math.abs(Math.sin(ztheta*Math.PI/180.f));
double f2 = Math.abs(Math.sin(xtheta*Math.PI/180.0f))+Math.abs(Math.cos(xtheta*Math.PI/180.0f))*f1;
mat.scale(dxCurves/f1, dyCurves/f2, dxCurves/f1);
mat.translate(dxFrame / 2, dyFrame / 2, dxFrame / 2);
// curve matrix
Matrix3D curveMatrix = new Matrix3D();
curveMatrix.unit();
curveMatrix.translate(-xmin, -ymin, -zmin);
curveMatrix.scale(1/dx, 1/dx, 1/dz);
curveMatrix.mult(mat);
double xPlane = (ztheta >= 0 && ztheta <= 180 ? 0 : 1);
double yPlane = (ztheta >= 270 || ztheta <= 90 ? 0 : 1);
double zPlane = (xtheta < 90 ? 1 : 0);
g.setColor(Color.white);
fill3DPlane(g, new double[] {0,1}, yPlane, new double[] {0,1});
fill3DPlane(g, xPlane, new double[] {0,1}, new double[] {0,1});
fill3DPlane(g, new double[] {0,1}, new double[] {0,1}, zPlane);
Graphics2D g2d = (Graphics2D)g;
Stroke normS = g2d.getStroke();
int xlabelWidthMax = 0, ylabelWidthMax = 0, zlabelWidthMax = 0;
// X Grid
boolean doXGrid = XGridP.isSet() && !XGridStyleP.is("none");
double[] xticks = XTickP.getArray();
String[] xticklabels = XTickLabelP.getArray();
Stroke xS = XGridStyleP.getStroke();
g2d.setColor(XColorP.getColor());
for (int i=0; i<xticks.length; i++)
{
double xf = (xticks[i] - xmin) / (xmax - xmin);
// grid line
if (doXGrid)
{
g2d.setStroke(xS);
draw3DLine(g, xf, 0, zPlane, xf, 1, zPlane);
draw3DLine(g, xf, yPlane, 0, xf, yPlane, 1);
g2d.setStroke(normS);
}
// tick mark
draw3DLine(g, xf,1-yPlane,zPlane, xf,1.03-1.06*yPlane,zPlane);
// tick text
if (i < xticklabels.length)
{
int sXWidth = fM.stringWidth(xticklabels[i]);
Point pt = mat.transform(xf, 1.03-1.06*yPlane, zPlane);
g.drawString(xticklabels[i],
(xPlane != yPlane ? pt.x+5 : pt.x-sXWidth-5),
(zPlane > 0 ? dyFrame-pt.y : dyFrame-pt.y+sAscent));
if (sXWidth > xlabelWidthMax)
xlabelWidthMax = sXWidth;
}
}
// Y Grid
boolean doYGrid = YGridP.isSet() && !YGridStyleP.is("none");
double[] yticks = YTickP.getArray();
String[] yticklabels = YTickLabelP.getArray();
Stroke yS = YGridStyleP.getStroke();
g2d.setColor(YColorP.getColor());
for (int i=0; i<yticks.length; i++)
{
double yf = (yticks[i] - ymin) / (ymax - ymin);
// grid line
if (doYGrid)
{
g2d.setStroke(yS);
draw3DLine(g, 0, yf, zPlane, 1, yf, zPlane);
draw3DLine(g, xPlane, yf, 0, xPlane, yf, 1);
g2d.setStroke(normS);
}
// tick mark
draw3DLine(g, 1-xPlane,yf,zPlane, 1.03-1.06*xPlane,yf,zPlane);
// tick text
if (i < yticklabels.length)
{
int sYWidth = fM.stringWidth(yticklabels[i]);
Point pt = mat.transform(1.03-1.06*xPlane, yf, zPlane);
g.drawString(yticklabels[i],
(xPlane == yPlane ? pt.x+5 : pt.x-sYWidth-5),
(zPlane > 0 ? dyFrame-pt.y : dyFrame-pt.y+sAscent));
if (sYWidth > ylabelWidthMax)
ylabelWidthMax = sYWidth;
}
}
// Z Grid
boolean doZGrid = ZGridP.isSet() && !ZGridStyleP.is("none");
double[] zticks = ZTickP.getArray();
String[] zticklabels = ZTickLabelP.getArray();
Stroke zS = ZGridStyleP.getStroke();
g2d.setColor(ZColorP.getColor());
for (int i=0; i<zticks.length; i++)
{
double zf = (zticks[i] - zmin) / (zmax - zmin);
// grid line
if (doZGrid)
{
g2d.setStroke(yS);
draw3DLine(g, xPlane, 0, zf, xPlane, 1, zf);
draw3DLine(g, 0, yPlane, zf, 1, yPlane, zf);
g2d.setStroke(normS);
}
// tick mark
draw3DLine(g, yPlane,1-xPlane,zf, 1.06*yPlane-0.03,1-xPlane,zf);
// tick text
if (i < zticklabels.length)
{
int sZWidth = fM.stringWidth(zticklabels[i]);
Point pt = mat.transform(1.06*yPlane-0.03, 1-xPlane, zf);
g.drawString(zticklabels[i], pt.x-sZWidth-5,
(zPlane > 0 ? dyFrame-pt.y+sAscent : dyFrame-pt.y));
if (sZWidth > zlabelWidthMax)
zlabelWidthMax = sZWidth;
}
}
// axis
g.setColor(XColorP.getColor());
draw3DLine(g, 0,1-yPlane,zPlane, 1,1-yPlane,zPlane);
g.setColor(YColorP.getColor());
draw3DLine(g, 1-xPlane,0,zPlane, 1-xPlane,1,zPlane);
g.setColor(ZColorP.getColor());
draw3DLine(g, yPlane,1-xPlane,0, yPlane,1-xPlane,1);
// plot line objects
for(int n = 0; n < ChildrenP.size(); n++)
{
//((GraphicalObject)axesElements.elementAt(n)).setPlotArea(dxOrig,dyFrame-dyOrig,dxCurves,dyCurves);
((GraphicalObject)ChildrenP.elementAt(n)).setPlotArea(0,dyFrame,dxCurves,dyCurves);
((GraphicalObject)ChildrenP.elementAt(n)).mat = curveMatrix;
((GraphicalObject)ChildrenP.elementAt(n)).paint(g);
}
g.setColor(Color.black);
// title
if (title != null)
{
title.setPlotArea(dxOrig+dxCurves/2, dyOrig-5, 0, 0);
title.paint(g);
}
// X label
g.setColor(XColorP.getColor());
if (xLabel != null)
{
Point pt = mat.transform(0.5, 1.03-1.06*yPlane, zPlane);
xLabel.setRotation(0);
xLabel.setAlign(
(xPlane != yPlane ? TextObject.H_LEFT : TextObject.H_RIGHT),
(zPlane > 0 ? TextObject.V_BOTTOM : TextObject.V_TOP));
xLabel.setPlotArea(
(xPlane != yPlane ? pt.x+xlabelWidthMax+5 : pt.x-xlabelWidthMax-5),
(zPlane > 0 ? dyFrame-pt.y-sAscent : dyFrame-pt.y+sAscent),
0, 0);
xLabel.paint(g);
}
// Y label
g.setColor(YColorP.getColor());
if (yLabel != null)
{
Point pt = mat.transform(1.03-1.06*xPlane, 0.5, zPlane);
yLabel.setRotation(0);
yLabel.setAlign(
(xPlane == yPlane ? TextObject.H_LEFT : TextObject.H_RIGHT),
(zPlane > 0 ? TextObject.V_BOTTOM : TextObject.V_TOP));
yLabel.setPlotArea(
(xPlane == yPlane ? pt.x+ylabelWidthMax+5 : pt.x-ylabelWidthMax-5),
(zPlane > 0 ? dyFrame-pt.y-sAscent : dyFrame-pt.y+sAscent),
0, 0);
yLabel.paint(g);
}
// Z label
g.setColor(ZColorP.getColor());
if (zLabel != null)
{
Point pt = mat.transform(1.06*yPlane-0.03, 1-xPlane, 0.5);
zLabel.setRotation(-90);
zLabel.setPlotArea(pt.x-zlabelWidthMax-10, dyFrame-pt.y, 0, 0);
zLabel.paint(g);
}
flushBackBuffer(_g, g);
setPainted(); //?
}
public void draw3DLine(Graphics g, double x0, double y0, double z0,
double x1, double y1, double z1)
{
double[] x= {x0, x1};
double[] y= {y0, y1};
double[] z= {z0, z1};
int[] tx = new int[2];
int[] ty = new int[2];
int[] tz = new int[2];
mat.transform(x, y, z, tx, ty, tz);
g.drawLine(tx[0], dyFrame - ty[0], tx[1], dyFrame - ty[1]);
}
private void fill3DPlane(Graphics g, double[] x, double y, double[] z)
{
fill3DPlane(
g,
new double[] {x[0], x[1], x[1], x[0]},
new double[] {y, y, y, y},
new double[] {z[0], z[0], z[1], z[1]}
);
}
private void fill3DPlane(Graphics g, double x, double[] y, double[] z)
{
fill3DPlane(
g,
new double[] {x, x, x, x},
new double[] {y[0], y[1], y[1], y[0]},
new double[] {z[0], z[0], z[1], z[1]}
);
}
private void fill3DPlane(Graphics g, double x[], double[] y, double z)
{
fill3DPlane(
g,
new double[] {x[0], x[0], x[1], x[1]},
new double[] {y[0], y[1], y[1], y[0]},
new double[] {z, z, z, z}
);
}
private void fill3DPlane(Graphics g, double[] x, double[] y, double[] z)
{
int[] ix = new int[x.length];
int[] iy = new int[y.length];
int[] iz = new int[z.length];
mat.transform(x, y, z, ix, iy, iz);
for (int i=0; i<iy.length; i++)
iy[i] = dyFrame - iy[i];
g.fillPolygon(ix, iy, ix.length);
}
public void mousePressed(MouseEvent e)
{
prevx = e.getX();
prevy = e.getY();
e.consume();
boxVisible = true;
}
public void mouseClicked(MouseEvent e) { }
public void mouseReleased(MouseEvent e)
{
boxVisible = false;
if (painted) {
painted = false;
repaint();
}
}
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseMoved(MouseEvent e) { }
public void mouseDragged(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
ztheta -= (x - prevx) * (360.0 / getSize().width);
xtheta -= (prevy - y) * (360.0 / getSize().height);
if (xtheta < 0) xtheta = 0;
else if (xtheta > 180) xtheta = 180;
if (ztheta > 360) ztheta -= 360;
else if (ztheta < 0) ztheta += 360;
// compute roational matrix and change axes matrix
rotMat = makeRotMatrix();
if (painted) {
painted = false;
repaint();
}
prevx = x;
prevy = y;
e.consume();
}
private synchronized void setPainted() {
painted = true;
notifyAll();
}
// private synchronized void waitPainted()
// {
// while (!painted)
// {
// try {
// wait();
// }
// catch (InterruptedException e) {}
// }
// painted = false;
// }
public void rotate(double phiX, double phiY, double phiZ)
{
// compute roational matrix and change axes matrix
Matrix3D mat = new Matrix3D();
mat.unit();
mat.xrot(phiX);
mat.yrot(phiY);
mat.zrot(phiZ);
rotMat.mult(mat);
if (painted) {
painted = false;
repaint();
}
}
}