// ------------------------------------------------------- // DrawPanel - Subclass of Panel, the canvas upon which // we draw our 3d function // ------------------------------------------------------- import java.util.HashMap; import javax.swing.*; import java.awt.*; public class DrawPanel extends JPanel { private static final double RADIANS_PER_DEGREE = Math.PI / 180.0; private static final double FACTOR1 = .4; private static final double FACTOR2 = .05; private static final double FACTOR3 = 1.1; private double mCosX = 0.0; private double mCosY = 0.0; private double mCosZ = 0.0; private double mSinX = 0.0; private double mSinY = 0.0; private double mSinZ= 0.0; private int mXOffset = 0; private int mYOffset = 0; private Point mValues[][] = null; public DrawPanel() { setPreferredSize(new Dimension(0, 400)); setBorder( BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder(2, 2, 2, 2), BorderFactory.createEtchedBorder() ) ); } public void update( int xDegrees, int yDegrees, int zDegrees, int nDivisionsX, int nDivisionsY, double xStart, double yStart, double xEnd, double yEnd, Node n, UpdateErrorObserver observer ) { // Set mValues for 3D => 2D transformation mCosX = Math.cos(xDegrees * RADIANS_PER_DEGREE); mCosY = Math.cos(yDegrees * RADIANS_PER_DEGREE); mCosZ = Math.cos(zDegrees * RADIANS_PER_DEGREE); mSinX = Math.sin(xDegrees * RADIANS_PER_DEGREE); mSinY = Math.sin(yDegrees * RADIANS_PER_DEGREE); mSinZ = Math.sin(zDegrees * RADIANS_PER_DEGREE); // Create our mValues array double xStep = (xEnd - xStart) / (double)nDivisionsX; double yStep = (yEnd - yStart) / (double)nDivisionsY; ++nDivisionsX; ++nDivisionsY; mValues = new Point[nDivisionsX][nDivisionsY]; HashMap table = new HashMap<>(); try { int i = 0; for(double x = xStart; x <= xEnd; x += xStep, i ++) { table.put("x", x); int j = 0; for(double y = yStart; y <= yEnd; y += yStep, j ++) { table.put("y", y); double z = n.evaluate(table); mValues[i][j] = to2D(x, y, z); } } } catch(Exception e) { observer.updateErrorOccurred(e.getMessage()); mValues = null; return; } // Now that all our mValues have been // updated, we can render our 3d function repaint(); } private Point to2D(double x, double y, double z) { double vx = x * mCosX + y * mCosY + z * mCosZ; double vy = x * mSinX + y * mSinY + z * mSinZ; return(new Point((int)(vx + 0.5), (int)(vy + 0.5))); } private Point translate(Point p) { Point newPoint = new Point(p); newPoint.translate(mXOffset, mYOffset); return(newPoint); } public void paint(Graphics g) { super.paint(g); if(mValues == null) return; Dimension d = getSize(); mXOffset = d.width / 2; mYOffset = d.height / 2; double axisLength = FACTOR1 * Math.min(d.width, d.height); g.setColor(Color.blue); drawAxes(g, axisLength); g.setColor(Color.blue); Point p1 = null; Point p2 = null; for(int i = 0; i < mValues.length; i ++) { for(int j = 1; j < mValues[i].length; j ++) { p1 = translate(mValues[i][j - 1]); p2 = translate(mValues[i][j]); g.drawLine(p1.x, p1.y, p2.x, p2.y); } } for(int j = 0; j < mValues[0].length; j ++) { for(int i = 1; i < mValues.length; i ++) { p1 = translate(mValues[i - 1][j]); p2 = translate(mValues[i][j]); g.drawLine(p1.x, p1.y, p2.x, p2.y); } } } private void drawAxes(Graphics g, double axisLength) { Point center = translate(to2D(0.0, 0.0, 0.0)); Point xEnd = translate(to2D(axisLength, 0.0, 0.0)); Point yEnd = translate(to2D(0.0, axisLength, 0.0)); Point zEnd = translate(to2D(0.0, 0.0, axisLength)); drawAxis(center, xEnd, "x", g); drawAxis(center, yEnd, "y", g); drawAxis(center, zEnd, "z", g); } private void drawAxis(Point center, Point end, String name, Graphics g) { g.drawLine(center.x, center.y, end.x, end.y); // First draw an arrowhead double deltaX = center.x - end.x; double deltaY = center.y - end.y; double theta = 0.0; if(deltaX == 0.0) theta = (deltaY >= 0.0 ? Math.PI / 2.0 : 3.0 * Math.PI / 2.0); else if(deltaY == 0.0) theta = (deltaX >= 0.0 ? 0.0 : Math.PI); else theta = Math.atan2(deltaY, deltaX); double r = Math.sqrt(deltaX * deltaX + deltaY * deltaY); double distance = r * FACTOR2; double angle = theta + 20 * RADIANS_PER_DEGREE; Point side1 = new Point( (int)(end.x + distance * Math.cos(angle) + 0.5), (int)(end.y + distance * Math.sin(angle) + 0.5) ); angle = theta - 20 * RADIANS_PER_DEGREE; Point side2 = new Point( (int)(end.x + distance * Math.cos(angle) + 0.5), (int)(end.y + distance * Math.sin(angle) + 0.5) ); g.drawLine(end.x, end.y, side1.x, side1.y); g.drawLine(end.x, end.y, side2.x, side2.y); // Now label the axis theta += Math.PI; distance = r * FACTOR3; Point p = new Point( (int)(center.x + distance * Math.cos(theta) + 0.5), (int)(center.y + distance * Math.sin(theta) + 0.5) ); g.drawString(name, p.x, p.y); } }