import java.applet.*; import java.awt.*; import java.awt.event.*; import java.text.*; import go.*; import goText.*; class FunctionWithText extends GoDrawableWithText { // // The function. // double fxy(double x, double y) { return Math.sin(x + y); } // Function data double xMin, yMin, zMin; double xMax, yMax, zMax; double xMinTotal, yMinTotal, zMinTotal; double xMaxTotal, yMaxTotal, zMaxTotal; int triangleStripNum; int lineStripNum; GoVertex[] triangleStripData; GoVertex[] lineStripData; double[] normal = new double[3]; // // Constructor. // FunctionWithText( // // Context // Go go, // // Function range & resolution // double xMin, double xMax, double yMin, double yMax, double zMin, double zMax, int xDiv, int yDiv, // // X-axis text values that work with initial view. // double xMinText, double xMaxText, int xDivText, int xTextMode, double xXPath, double xYPath, double xZPath, double xXUp, double xYUp, double xZUp, int xYPosition, double xYOffset, int xZPosition, double xZOffset, int xAlignment, // // Y-axis text values that work with initial view. // double yMinText, double yMaxText, int yDivText, int yTextMode, double yXPath, double yYPath, double yZPath, double yXUp, double yYUp, double yZUp, int yXPosition, double yXOffset, int yZPosition, double yZOffset, int yAlignment, // // Z-axis text values that work with initial view. // double zMinText, double zMaxText, int zDivText, int zTextMode, double zXPath, double zYPath, double zZPath, double zXUp, double zYUp, double zZUp, int zXPosition, double zXOffset, int zYPosition, double zYOffset, int zAlignment) { this.xMinText = xMinText; this.xMaxText = xMaxText; this.xDivText = xDivText; this.xTextMode = xTextMode; this.xXPath = xXPath; this.xYPath = xYPath; this.xZPath = xZPath; this.xXUp = xXUp; this.xYUp = xYUp; this.xZUp = xZUp; this.xYPosition = xYPosition; this.xYOffset = xYOffset; this.xZPosition = xZPosition; this.xZOffset = xZOffset; this.xAlignment = xAlignment; this.yMinText = yMinText; this.yMaxText = yMaxText; this.yDivText = yDivText; this.yTextMode = yTextMode; this.yXPath = yXPath; this.yYPath = yYPath; this.yZPath = yZPath; this.yXUp = yXUp; this.yYUp = yYUp; this.yZUp = yZUp; this.yXPosition = yXPosition; this.yXOffset = yXOffset; this.yZPosition = yZPosition; this.yZOffset = yZOffset; this.yAlignment = yAlignment; this.zMinText = zMinText; this.zMaxText = zMaxText; this.zDivText = zDivText; this.zTextMode = zTextMode; this.zXPath = zXPath; this.zYPath = zYPath; this.zZPath = zZPath; this.zXUp = zXUp; this.zYUp = zYUp; this.zZUp = zZUp; this.zXPosition = zXPosition; this.zXOffset = zXOffset; this.zYPosition = zYPosition; this.zYOffset = zYOffset; this.zAlignment = zAlignment; triangleStripNum = xDiv; lineStripNum = xDiv + yDiv + 2; triangleStripData = new GoVertex[triangleStripNum]; lineStripData = new GoVertex[lineStripNum]; // // Plot the function within the zMin and zMax bounds. // this.xMin = xMin; this.yMin = yMin; this.zMin = zMin; this.xMax = xMax; this.yMax = yMax; this.zMax = zMax; plot(xMin, xMax, yMin, yMax, xDiv, yDiv); // // Create the function's bounding box and axis text. // createBox(this.xMin, this.yMin, this.zMin, this.xMax, this.yMax, this.zMax); // // Calculate the total bounding box. (function, box and axis text) // go.push(Go.RENDER_MODE); go.clear(Go.BOUND_BOX); go.renderMode(Go.BOUND_BOX); drawBox(go); go.pop(Go.RENDER_MODE); GoBoundBox boundBox = go.boundBox(); this.xMinTotal = boundBox.xMin(); this.yMinTotal = boundBox.yMin(); this.zMinTotal = boundBox.zMin(); this.xMaxTotal = boundBox.xMax(); this.yMaxTotal = boundBox.yMax(); this.zMaxTotal = boundBox.zMax(); // // Default drawing mode. // drawMode(SOLID); axisText(NO_AXIS); } // // Clamp function to Z range. // double fxyClamp(double x, double y) { double zVal = fxy(x, y); // // Chop off anything less than zMin or greater than zMax. // if(zVal < zMin) { return zMin; } else if(zVal > zMax) { return zMax; } else { return zVal; } } // // Derivative of function with respect to x. (used to calc normals) // double dfxy_dx(double x, double y) { double delta = 0.0000001; return 1.0/(2.0 * delta) * (fxy(x + delta, y) - fxy(x - delta, y)); } // // Derivative of function with respect to y. (used to calc normals) // double dfxy_dy(double x, double y) { double delta = 0.0000001; return 1.0/(2.0 * delta) * (fxy(x, y + delta) - fxy(x, y - delta)); } // // Normal vector at f(x, y) // void normal(double x, double y, double[] n) { double dx = dfxy_dx(x, y); double dy = dfxy_dy(x, y); double den = Math.sqrt(1.0 + dx * dx + dy * dy); n[0] = dx / den; n[1] = dy / den; n[2] = 1.0 / den; } void drawSolid(Go go) { for(int i = 0; i < triangleStripNum; i++) { go.render(triangleStripData[i]); } } void drawWire(Go go) { for(int i = 0; i < lineStripNum; i++) { go.render(lineStripData[i]); } } void draw(Go go) { switch(drawMode) { case GoDrawableWithText.SOLID: if(axisText() == NO_AXIS) { go.color(1, 1, 1); // white drawSolid(go); go.color(1, 0, 0); // red drawWire(go); } go.color(0, 0, 0); // black drawBox(go); break; case GoDrawableWithText.WIRE: if(axisText() == NO_AXIS) { go.color(1, 0, 0); // red drawWire(go); } go.color(0, 0, 0); // black drawBox(go); break; case GoDrawableWithText.BOX: go.color(0, 0, 0); // black drawBox(go); break; } } void plot(double xMin, double xMax, double yMin, double yMax, int xDiv, int yDiv) { int i, j, count; double x, y; double xInc = (xMax - xMin) / xDiv; double yInc = (yMax - yMin) / yDiv; // // Calc lineStripData. // count = 0; for(i = 0, x = xMin; i <= xDiv; i++, x += xInc, count++) { lineStripData[count] = new GoLineStrip(yDiv + 1); for(j = 0, y = yMin; j < yDiv + 1; j++, y += yInc) { lineStripData[count].xyz(j, x, y, fxyClamp(x, y)); } } for(i = 0, y = yMin; i <= yDiv; i++, y += yInc, count++) { lineStripData[count] = new GoLineStrip(xDiv + 1); for(j = 0, x = xMin; j < xDiv + 1; j++, x += xInc) { lineStripData[count].xyz(j, x, y, fxyClamp(x, y)); } } // // Calc triangleStripData. // count = 0; for(i = 0, x = xMin; i < xDiv; i++, x += xInc, count++) { triangleStripData[count] = new GoTriangleStrip(yDiv * 2 + 2, Go.NORMAL); triangleStripData[count].xyz(0, x, yMin, fxyClamp(x, yMin)); normal(x, yMin, normal); triangleStripData[count].ijk(0, normal[0], normal[1], normal[2]); triangleStripData[count].xyz(1, x + xInc, yMin, fxyClamp(x + xInc, yMin)); normal(x + xInc, yMin, normal); triangleStripData[count].ijk(1, normal[0], normal[1], normal[2]); for(j = 1, y = yMin + yInc; j <= yDiv; j++, y += yInc) { triangleStripData[count].xyz(j * 2, x, y, fxyClamp(x, y)); normal(x, y, normal); triangleStripData[count].ijk(j * 2, normal[0], normal[1], normal[2]); triangleStripData[count].xyz(j * 2 + 1, x + xInc, y, fxyClamp(x + xInc, y)); normal(x + xInc, y, normal); triangleStripData[count].ijk(j * 2 + 1, normal[0], normal[1], normal[2]); } } } } abstract class GoDrawableWithText { final static int SOLID = 0; final static int WIRE = 1; final static int BOX = 2; final static int X_AXIS = 0; final static int Y_AXIS = 1; final static int Z_AXIS = 2; final static int NO_AXIS = 3; final static int AXIS_MIN = 0; final static int AXIS_MAX = 1; int drawMode; // // box // double xMin, yMin, zMin; double xMax, yMax, zMax; GoVertex top; GoVertex bottom; GoVertex sides; GoVertex xTicks, yTicks, zTicks; GoVertex axes; GoText X, Y, Z; int axisText = X_AXIS; // Initialize to allow axes to be included // in overall bound box calculations. // X-axis default text values GoText[] xText; double xMinText; double xMaxText; int xDivText; int xTextMode; double xXPath; double xYPath; double xZPath; double xXUp; double xYUp; double xZUp; int xYPosition; double xYOffset; int xZPosition; double xZOffset; int xAlignment; // Y-axis default text values GoText[] yText; double yMinText; double yMaxText; int yDivText; int yTextMode; double yXPath; double yYPath; double yZPath; double yXUp; double yYUp; double yZUp; int yXPosition; double yXOffset; int yZPosition; double yZOffset; int yAlignment; // Z-axis default text values GoText[] zText; double zMinText; double zMaxText; int zDivText; int zTextMode; double zXPath; double zYPath; double zZPath; double zXUp; double zYUp; double zZUp; int zXPosition; double zXOffset; int zYPosition; double zYOffset; int zAlignment; abstract void draw(Go go); void createBox(double xMin, double yMin, double zMin, double xMax, double yMax, double zMax) { this.xMin = xMin; this.yMin = yMin; this.zMin = zMin; this.xMax = xMax; this.yMax = yMax; this.zMax = zMax; top = new GoLineLoop(4); top.xyz(0, xMin, yMax, zMin); top.xyz(1, xMin, yMax, zMax); top.xyz(2, xMax, yMax, zMax); top.xyz(3, xMax, yMax, zMin); bottom = new GoLineLoop(4); bottom.xyz(0, xMin, yMin, zMin); bottom.xyz(1, xMin, yMin, zMax); bottom.xyz(2, xMax, yMin, zMax); bottom.xyz(3, xMax, yMin, zMin); sides = new GoLines(8); sides.xyz(0, xMin, yMin, zMin); sides.xyz(1, xMin, yMax, zMin); sides.xyz(2, xMax, yMin, zMin); sides.xyz(3, xMax, yMax, zMin); sides.xyz(4, xMin, yMin, zMax); sides.xyz(5, xMin, yMax, zMax); sides.xyz(6, xMax, yMin, zMax); sides.xyz(7, xMax, yMax, zMax); // // Axes. // axes = new GoLines(6); // Length that axis is drawn outside of box. double length = Math.sqrt((xMax - xMin) * (xMax - xMin) + (yMax - yMin) * (yMax - yMin) + (zMax - zMin) * (zMax - zMin)) / 10.0; // Offset of axis text. double axisTextOffset = length / 2.0; // Scale of axis text. double axisTextScale = 0.7; // Font of axis text. GoFont axisFont = new GoHershey("hersheyFonts/times.i"); // X - axis axes.xyz(0, xMax, yMin, zMin); axes.xyz(1, xMax + length, yMin, zMin); X = new GoText(xMax + length + axisTextOffset, yMin, zMin, /* position */ 1.0, 0.0, /* path */ axisTextScale, axisTextScale, /* scale */ GoText.CENTER_CENTER, /* alignment */ axisFont, /* font */ "X"); /* text */ // Y - axis axes.xyz(2, xMin, yMax, zMin); axes.xyz(3, xMin, yMax + length, zMin); Y = new GoText(xMin, yMax + length + axisTextOffset, zMin, /* position */ 1.0, 0.0, /* path */ axisTextScale, axisTextScale, /* scale */ GoText.CENTER_CENTER, /* alignment */ axisFont, /* font */ "Y"); /* text */ // Z - axis axes.xyz(4, xMin, yMin, zMax); axes.xyz(5, xMin, yMin, zMax + length); Z = new GoText(xMin, yMin, zMax + length + axisTextOffset, /* position */ 1.0, 0.0, /* path */ axisTextScale, axisTextScale, /* scale */ GoText.CENTER_CENTER, /* alignment */ axisFont, /* font */ "Z"); /* text */ int i, j; double x, y, z, inc; // // Create X-axis ticks // xTicks = new GoLines((xDivText + 1) * 8); for(i = 0, j = 0, x = xMinText, inc = (xMaxText - xMinText) / xDivText; i <= xDivText; i++, x += inc) { if(x != xMin && x != xMax) { xTicks.xyz(j*8, x, yMin, zMin); xTicks.xyz(j*8+1, x, yMin, zMax); xTicks.xyz(j*8+2, x, yMin, zMax); xTicks.xyz(j*8+3, x, yMax, zMax); xTicks.xyz(j*8+4, x, yMax, zMax); xTicks.xyz(j*8+5, x, yMax, zMin); xTicks.xyz(j*8+6, x, yMax, zMin); xTicks.xyz(j*8+7, x, yMin, zMin); j++; } else { xTicks.remove(j*8, 8); } } // // Create Y-axis ticks // yTicks = new GoLines((yDivText + 1) * 8); for(i = 0, j = 0, y = yMinText, inc = (yMaxText - yMinText) / yDivText; i <= yDivText; i++, y += inc) { if(y != yMin && y != yMax) { yTicks.xyz(j*8, xMin, y, zMin); yTicks.xyz(j*8+1, xMin, y, zMax); yTicks.xyz(j*8+2, xMin, y, zMax); yTicks.xyz(j*8+3, xMax, y, zMax); yTicks.xyz(j*8+4, xMax, y, zMax); yTicks.xyz(j*8+5, xMax, y, zMin); yTicks.xyz(j*8+6, xMax, y, zMin); yTicks.xyz(j*8+7, xMin, y, zMin); j++; } else { yTicks.remove(j*8, 8); } } // // Create Z-axis ticks // zTicks = new GoLines((zDivText + 1) * 8); for(i = 0, j = 0, z = zMinText, inc = (zMaxText - zMinText) / zDivText; i <= zDivText; i++, z += inc) { if(z != zMin && z != zMax) { zTicks.xyz(j*8, xMin, yMin, z); zTicks.xyz(j*8+1, xMin, yMax, z); zTicks.xyz(j*8+2, xMin, yMax, z); zTicks.xyz(j*8+3, xMax, yMax, z); zTicks.xyz(j*8+4, xMax, yMax, z); zTicks.xyz(j*8+5, xMax, yMin, z); zTicks.xyz(j*8+6, xMax, yMin, z); zTicks.xyz(j*8+7, xMin, yMin, z); j++; } else { zTicks.remove(j*8, 8); } } // // Create the font to be used for axis text // GoFont font = new GoHershey("hersheyFonts/meteorology"); // // Setup the axis text number format // NumberFormat nf = NumberFormat.getInstance(); nf.setMinimumFractionDigits(1); nf.setMaximumFractionDigits(1); // // Create X-axis text // xText = new GoText[xDivText + 1]; for(i = 0, x = xMinText, inc = (xMaxText - xMinText) / xDivText; i <= xDivText; i++, x += inc) { String string = nf.format(x); if(xTextMode == GoText.MODE_2D) { xText[i] = new GoText(0.0, 0.0, 0.0, /* position (set after this loop) */ xXPath, xYPath, /* path */ 0.6, 0.6, /* scale */ xAlignment, /* alignment */ font, /* font */ string); /* text */ } else { xText[i] = new GoText(0.0, 0.0, 0.0, /* position (set after this loop) */ xXPath, xYPath, xZPath, /* path */ xXUp, xYUp, xZUp, /* up */ 0.6, 0.6, /* scale */ xAlignment, /* alignment */ font, /* font */ string); /* text */ } } // set position position(X_AXIS, xYPosition, xYOffset, xZPosition, xZOffset); // // Create Y-axis text // yText = new GoText[yDivText + 1]; for(i = 0, y = yMinText, inc = (yMaxText - yMinText) / yDivText; i <= yDivText; i++, y += inc) { String string = nf.format(y); if(yTextMode == GoText.MODE_2D) { yText[i] = new GoText(0.0, 0.0, 0.0, /* position (set after this loop) */ yXPath, yYPath, /* path */ 0.6, 0.6, /* scale */ yAlignment, /* alignment */ font, /* font */ string); /* text */ } else { yText[i] = new GoText(0.0, 0.0, 0.0, /* position (set after this loop) */ yXPath, yYPath, yZPath, /* path */ yXUp, yYUp, yZUp, /* up */ 0.6, 0.6, /* scale */ yAlignment, /* alignment */ font, /* font */ string); /* text */ } } // set position position(Y_AXIS, yXPosition, yXOffset, yZPosition, yZOffset); // // Create Z-axis text // zText = new GoText[zDivText + 1]; for(i = 0, z = zMinText, inc = (zMaxText - zMinText) / zDivText; i <= zDivText; i++, z += inc) { String string = nf.format(z); if(zTextMode == GoText.MODE_2D) { zText[i] = new GoText(0.0, 0.0, 0.0, /* position (set after this loop) */ zXPath, zYPath, /* path */ 0.6, 0.6, /* scale */ zAlignment, /* alignment */ font, /* font */ string); /* text */ } else { zText[i] = new GoText(0.0, 0.0, 0.0, /* position (set after this loop) */ zXPath, zYPath, zZPath, /* path */ zXUp, zYUp, zZUp, /* up */ 0.6, 0.6, /* scale */ zAlignment, /* alignment */ font, /* font */ string); /* text */ } } // set position position(Z_AXIS, zXPosition, zXOffset, zYPosition, zYOffset); } void drawBox(Go go) { // // Render box. // go.render(top); go.render(bottom); go.render(sides); // // Render help axis while setting up text. // if(axisText != NO_AXIS) { go.push(go.COLOR); go.color(0, 0, 1); go.render(axes); X.render(go); Y.render(go); Z.render(go); go.pop(go.COLOR); } // // Render axis text & ticks. // if(axisText != Y_AXIS && axisText != Z_AXIS) { go.render(xTicks); for(int i = 0; i <= xDivText; i++) { xText[i].render(go); } } if(axisText != X_AXIS && axisText != Z_AXIS) { go.render(yTicks); for(int i = 0; i <= yDivText; i++) { yText[i].render(go); } } if(axisText != X_AXIS && axisText != Y_AXIS) { go.render(zTicks); for(int i = 0; i <= zDivText; i++) { zText[i].render(go); } } } void drawMode(int mode) { drawMode = mode; } int drawMode() { return drawMode; } void axisText(int mode) { axisText = mode; } int axisText() { return axisText; } void mode(int axis, int mode) { GoText[] text; int div; switch(axis) { case X_AXIS: default: text = xText; div = xDivText; break; case Y_AXIS: text = yText; div = yDivText; break; case Z_AXIS: text = zText; div = zDivText; break; } for(int i = 0; i <= div; i++) { text[i].mode(mode); } } void path(int axis, double x, double y, double z) { GoText[] text; int div; switch(axis) { case X_AXIS: default: text = xText; div = xDivText; break; case Y_AXIS: text = yText; div = yDivText; break; case Z_AXIS: text = zText; div = zDivText; break; } for(int i = 0; i <= div; i++) { text[i].path(x, y, z); } } void up(int axis, double x, double y, double z) { GoText[] text; int div; switch(axis) { case X_AXIS: default: text = xText; div = xDivText; break; case Y_AXIS: text = yText; div = yDivText; break; case Z_AXIS: text = zText; div = zDivText; break; } for(int i = 0; i <= div; i++) { text[i].up(x, y, z); } } void alignment(int axis, int alignment) { GoText[] text; int div; switch(axis) { case X_AXIS: default: text = xText; div = xDivText; break; case Y_AXIS: text = yText; div = yDivText; break; case Z_AXIS: text = zText; div = zDivText; break; } for(int i = 0; i <= div; i++) { text[i].alignment(alignment); } } void position(int axis, int axis1, double offset1, int axis2, double offset2) { GoText[] text; double num; int div; double inc; double min1, max1; double min2, max2; switch(axis) { case X_AXIS: default: text = xText; num = xMinText; div = xDivText; inc = (xMaxText - xMinText) / xDivText; min1 = yMin; max1 = yMax; min2 = zMin; max2 = zMax; break; case Y_AXIS: text = yText; num = yMinText; div = yDivText; inc = (yMaxText - yMinText) / yDivText; min1 = xMin; max1 = xMax; min2 = zMin; max2 = zMax; break; case Z_AXIS: text = zText; num = zMinText; div = zDivText; inc = (zMaxText - zMinText) / zDivText; min1 = xMin; max1 = xMax; min2 = yMin; max2 = yMax; break; } if(axis1 == AXIS_MIN && axis2 == AXIS_MIN) { for(int i = 0; i <= div; i++) { switch(axis) { case X_AXIS: text[i].position(num, min1 - offset1, min2 - offset2); break; case Y_AXIS: text[i].position(min1 - offset1, num, min2 - offset2); break; case Z_AXIS: text[i].position(min1 - offset1, min2 - offset2, num); break; } num += inc; } } else if(axis1 == AXIS_MIN && axis2 == AXIS_MAX) { for(int i = 0; i <= div; i++) { switch(axis) { case X_AXIS: text[i].position(num, min1 - offset1, max2 + offset2); break; case Y_AXIS: text[i].position(min1 - offset1, num, max2 + offset2); break; case Z_AXIS: text[i].position(min1 - offset1, max2 + offset2, num); break; } num += inc; } } else if(axis1 == AXIS_MAX && axis2 == AXIS_MAX) { for(int i = 0; i <= div; i++) { switch(axis) { case X_AXIS: text[i].position(num, max1 + offset1, max2 + offset2); break; case Y_AXIS: text[i].position(max1 + offset1, num, max2 + offset2); break; case Z_AXIS: text[i].position(max1 + offset1, max2 + offset2, num); break; } num += inc; } } else if(axis1 == AXIS_MAX && axis2 == AXIS_MIN) { for(int i = 0; i <= div; i++) { switch(axis) { case X_AXIS: text[i].position(num, max1 + offset1, min2 - offset2); break; case Y_AXIS: text[i].position(max1 + offset1, num, min2 - offset2); break; case Z_AXIS: text[i].position(max1 + offset1, min2 - offset2, num); break; } num += inc; } } } } class GoRotateWithTextPanel extends Panel { int rotateAbout = GoDrawableWithText.Y_AXIS; int rotateAs = GoDrawableWithText.WIRE; GoDrawableWithText drawable; Rotate rotate; public GoRotateWithTextPanel() { rotate = new Rotate(); } public void setup(GoDrawableWithText drawable, double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, double radius, boolean perspective) { this.drawable = drawable; // // Layout the panel. // setLayout(new BorderLayout()); add("West", new CardControls()); add("Center", rotate); rotate.setup(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, radius, perspective); } class Rotate extends GoInterface { // View variables. double eyeX; double eyeY; double eyeZ; double centerX; double centerY; double centerZ; double upX; double upY; double upZ; double radius; boolean perspective; // Rotate vector. double rX; double rY; double rZ; // Class temporary variables. GoMatrix modelview = new GoMatrix(); GoMatrix saveModelview = new GoMatrix(); int xStart, yStart; double angleStart; // // Interface render method. // public void render() { go.clear(go.IMAGE); go.renderMode(go.IMAGE); drawable.draw(go); swap(); } // // Interface resized method. // public void resized(int width, int height) { double dx = eyeX - centerX; double dy = eyeY - centerY; double dz = eyeZ - centerZ; double d = Math.sqrt(dx * dx + dy * dy + dz * dz); double fovy = 2.0 * 180.0/Math.PI * Math.atan(radius / d); double near = d - radius; double far = d + radius; double xUnits, yUnits; if(width >= height) { xUnits = 2 * radius * width / height; yUnits = 2 * radius; } else { xUnits = 2 * radius; yUnits = 2 * radius * height / width; } // setup projection matrix rotate.go.matrixMode(Go.PROJECTION); rotate.go.identity(); if(perspective) { if(width >= height) { rotate.go.perspective(fovy, xUnits / yUnits, near, far); } else { radius *= yUnits / xUnits; double fovyModified = Math.atan(radius / d) * 180.0 / Math.PI * 2.0; rotate.go.perspective(fovyModified, xUnits / yUnits, near, far); } } else { rotate.go.ortho(-xUnits / 2.0, xUnits / 2.0, -yUnits / 2.0, yUnits / 2.0, near, far); } rotate.go.matrixMode(Go.MODELVIEW); } // // Interface mousePressed method. // public void mousePressed(int x, int y) { // // Init mouse info. // xStart = x; yStart = y; angleStart = Math.atan2(go.height() / 2.0 - yStart, xStart - go.width() / 2.0); // // Save the current modelview matrix so that // it can be restored as the mouse is moved. // go.getModelview(saveModelview); // // Redisplay in rotateAs mode. // switch(rotateAs) { case GoDrawableWithText.SOLID: drawable.drawMode(drawable.SOLID); break; case GoDrawableWithText.WIRE: drawable.drawMode(drawable.WIRE); break; case GoDrawableWithText.BOX: drawable.drawMode(drawable.BOX); break; } render(); // // Calc the rotation vector // double x0 = 0.0; double y0 = 0.0; double z0 = 0.0; double x1; double y1; double z1; switch(rotateAbout) { case GoDrawableWithText.X_AXIS: x1 = 1.0; y1 = 0.0; z1 = 0.0; break; default: case GoDrawableWithText.Y_AXIS: x1 = 0.0; y1 = 1.0; z1 = 0.0; break; case GoDrawableWithText.Z_AXIS: x1 = 0.0; y1 = 0.0; z1 = 1.0; break; } go.push(go.MODELVIEW); go.inverse(); go.getModelview(modelview); go.pop(go.MODELVIEW); double[] m = modelview.m; double w = m[3] * x0 + m[7] * y0 + m[11] * z0 + m[15]; double x0N = (m[0] * x0 + m[4] * y0 + m[8] * z0 + m[12]) / w; double y0N = (m[1] * x0 + m[5] * y0 + m[9] * z0 + m[13]) / w; double z0N = (m[2] * x0 + m[6] * y0 + m[10] * z0 + m[14]) / w; w = m[3] * x1 + m[7] * y1 + m[11] * z1 + m[15]; double x1N = (m[0] * x1 + m[4] * y1 + m[8] * z1 + m[12]) / w; double y1N = (m[1] * x1 + m[5] * y1 + m[9] * z1 + m[13]) / w; double z1N = (m[2] * x1 + m[6] * y1 + m[10] * z1 + m[14]) / w; rX = x1N - x0N; rY = y1N - y0N; rZ = z1N - z0N; } // // Interface mouseReleased method. // public void mouseReleased(int x, int y) { drawable.drawMode(drawable.SOLID); render(); } // // Interface mouseDragged method. // public void mouseDragged(int x, int y) { int xEnd = x; int yEnd = y; go.load(saveModelview); double delta; switch(rotateAbout) { case GoDrawableWithText.X_AXIS: delta = (yEnd - yStart) / 2.0; break; default: case GoDrawableWithText.Y_AXIS: delta = (xEnd - xStart) / 2.0; break; case GoDrawableWithText.Z_AXIS: double angleEnd = Math.atan2(go.height() / 2.0 - yEnd, xEnd - go.width() / 2.0); delta = (angleEnd - angleStart) * 180.0 / Math.PI; break; } go.translate(centerX, centerY, centerZ); go.rotate(delta, rX, rY, rZ); go.translate(-centerX, -centerY, -centerZ); render(); } void setup(double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, double radius, boolean perspective) { this.eyeX = eyeX; this.eyeY = eyeY; this.eyeZ = eyeZ; this.centerX = centerX; this.centerY = centerY; this.centerZ = centerZ; this.upX = upX; this.upY = upY; this.upZ = upZ; this.radius = radius; this.perspective = perspective; // // Initialize the modelview matrix. // go.lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); } } class CardControls extends Panel implements ActionListener { CardLayout cardLayout = new CardLayout(); Panel cardCont = new Panel(cardLayout); CardControls() { setLayout(new BorderLayout()); // // Add control cards. // cardCont.add(new DisplayControls(), "Display"); cardCont.add(new TextControls(GoDrawableWithText.X_AXIS, drawable.xTextMode, drawable.xXPath, drawable.xYPath, drawable.xZPath, drawable.xXUp, drawable.xYUp, drawable.xZUp, drawable.xYPosition, drawable.xYOffset, drawable.xZPosition, drawable.xZOffset, drawable.xAlignment), "X Axis Text"); cardCont.add(new TextControls(GoDrawableWithText.Y_AXIS, drawable.yTextMode, drawable.yXPath, drawable.yYPath, drawable.yZPath, drawable.yXUp, drawable.yYUp, drawable.yZUp, drawable.yXPosition, drawable.yXOffset, drawable.yZPosition, drawable.yZOffset, drawable.yAlignment), "Y Axis Text"); cardCont.add(new TextControls(GoDrawableWithText.Z_AXIS, drawable.zTextMode, drawable.zXPath, drawable.zYPath, drawable.zZPath, drawable.zXUp, drawable.zYUp, drawable.zZUp, drawable.zXPosition, drawable.zXOffset, drawable.zYPosition, drawable.zYOffset, drawable.zAlignment), "Z Axis Text"); add("Center", cardCont); // // Add card selection buttons. // Panel cardSelection = new Panel(new GridLayout(1, 0)); Button button; cardSelection.add(button = new Button("Display")); button.addActionListener(this); cardSelection.add(button = new Button("X Axis Text")); button.addActionListener(this); cardSelection.add(button = new Button("Y Axis Text")); button.addActionListener(this); cardSelection.add(button = new Button("Z Axis Text")); button.addActionListener(this); add("North", cardSelection); } public void actionPerformed(ActionEvent evt) { String cmd = evt.getActionCommand(); if("Display".equals(cmd)) { cardLayout.show(cardCont, cmd); drawable.axisText(drawable.NO_AXIS); drawable.drawMode(drawable.SOLID); rotate.rerender(); } else if("X Axis Text".equals(cmd)) { cardLayout.show(cardCont, cmd); drawable.axisText(drawable.X_AXIS); drawable.drawMode(drawable.BOX); rotate.rerender(); } else if("Y Axis Text".equals(cmd)) { cardLayout.show(cardCont, cmd); drawable.axisText(drawable.Y_AXIS); drawable.drawMode(drawable.BOX); rotate.rerender(); } else if("Z Axis Text".equals(cmd)) { cardLayout.show(cardCont, cmd); drawable.axisText(drawable.Z_AXIS); drawable.drawMode(drawable.BOX); rotate.rerender(); } } } class DisplayControls extends Panel implements ItemListener { GridBagLayout gbl = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); Label label; CheckboxGroup cbRotateAsGroup = new CheckboxGroup(); Checkbox cbSolid; Checkbox cbWire; Checkbox cbBox; CheckboxGroup cbRotateAboutGroup = new CheckboxGroup(); Checkbox cbX; Checkbox cbY; Checkbox cbZ; DisplayControls() { setLayout(gbl); c.anchor = GridBagConstraints.WEST; // Rotate about. add(label = new Label("Rotate as:")); c.gridx = 0; c.gridy = 0; c.gridwidth = GridBagConstraints.REMAINDER; gbl.setConstraints(label, c); c.gridwidth = 1; // restore default add(cbSolid = new Checkbox("Solid", cbRotateAsGroup, false)); cbSolid.addItemListener(this); c.gridx = 0; c.gridy = 1; gbl.setConstraints(cbSolid, c); add(cbWire = new Checkbox("Wire", cbRotateAsGroup, true)); // default cbWire.addItemListener(this); c.gridx = 1; c.gridy = 1; gbl.setConstraints(cbWire, c); add(cbBox = new Checkbox("Box", cbRotateAsGroup, false)); cbBox.addItemListener(this); c.gridx = 2; c.gridy = 1; gbl.setConstraints(cbBox, c); // Separator add(label = new Label(" ")); c.gridx = 0; c.gridy = 2; c.gridwidth = GridBagConstraints.REMAINDER; gbl.setConstraints(label, c); // Rotate as. add(label = new Label("Rotate about:")); c.gridx = 0; c.gridy = 3; c.gridwidth = GridBagConstraints.REMAINDER; gbl.setConstraints(label, c); c.gridwidth = 1; // restore default add(cbX = new Checkbox("X", cbRotateAboutGroup, false)); cbX.addItemListener(this); c.gridx = 0; c.gridy = 4; gbl.setConstraints(cbX, c); add(cbY = new Checkbox("Y", cbRotateAboutGroup, true)); // default cbY.addItemListener(this); c.gridx = 1; c.gridy = 4; gbl.setConstraints(cbY, c); add(cbZ = new Checkbox("Z", cbRotateAboutGroup, false)); cbZ.addItemListener(this); c.gridx = 2; c.gridy = 4; gbl.setConstraints(cbZ, c); } public void itemStateChanged(ItemEvent event) { // // Set current "Rotate as" state. // Checkbox cb = cbRotateAsGroup.getSelectedCheckbox(); if(cb == cbSolid) { rotateAs = GoDrawableWithText.SOLID; } else if(cb == cbWire) { rotateAs = GoDrawableWithText.WIRE; } else if(cb == cbBox) { rotateAs = GoDrawableWithText.BOX; } // // Set current "Rotate about" state. // cb = cbRotateAboutGroup.getSelectedCheckbox(); if(cb == cbX) { rotateAbout = GoDrawableWithText.X_AXIS; } else if(cb == cbY) { rotateAbout = GoDrawableWithText.Y_AXIS; } else if(cb == cbZ) { rotateAbout = GoDrawableWithText.Z_AXIS; } } } class TextControls extends Panel { GridBagLayout gbl = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); Label modeLabel; ModeControls modeControls; Label pathLabel; PathControls pathControls; Label upLabel; UpControls upControls; Label positionLabel; PositionControls positionControls; Label alignmentLabel; AlignmentControls alignmentControls; TextControls(int axis, int textMode, double xPath, double yPath, double zPath, double xUp, double yUp, double zUp, int axisPosition1, double axisOffset1, int axisPosition2, double axisOffset2, int axisAlignment) { setLayout(gbl); // 2D or 3D add(modeLabel = new Label("Text Mode:")); c.gridx = 0; c.gridy = 0; c.gridwidth = 1; c.anchor = GridBagConstraints.EAST; gbl.setConstraints(modeLabel, c); modeControls = new ModeControls(axis, textMode); add(modeControls); c.gridx = 1; c.gridy = 0; c.gridwidth = GridBagConstraints.REMAINDER; c.anchor = GridBagConstraints.WEST; gbl.setConstraints(modeControls, c); // Path add(pathLabel = new Label("Path:")); c.gridx = 0; c.gridy = 1; c.gridwidth = 1; c.anchor = GridBagConstraints.EAST; gbl.setConstraints(pathLabel, c); pathControls = new PathControls(axis, xPath, yPath, zPath); add(pathControls); c.gridx = 1; c.gridy = 1; c.gridwidth = GridBagConstraints.REMAINDER; c.anchor = GridBagConstraints.WEST; gbl.setConstraints(pathControls, c); // Up add(upLabel = new Label("Up:")); c.gridx = 0; c.gridy = 2; c.gridwidth = 1; c.anchor = GridBagConstraints.EAST; gbl.setConstraints(upLabel, c); upControls = new UpControls(axis, xUp, yUp, zUp); add(upControls); c.gridx = 1; c.gridy = 2; c.gridwidth = GridBagConstraints.REMAINDER; c.anchor = GridBagConstraints.WEST; gbl.setConstraints(upControls, c); // Position add(positionLabel = new Label("Position:")); c.gridx = 0; c.gridy = 3; c.gridwidth = 1; c.anchor = GridBagConstraints.EAST; gbl.setConstraints(positionLabel, c); positionControls = new PositionControls(axis, axisPosition1, axisOffset1, axisPosition2, axisOffset2); add(positionControls); c.gridx = 1; c.gridy = 3; c.gridwidth = GridBagConstraints.REMAINDER; c.anchor = GridBagConstraints.WEST; gbl.setConstraints(positionControls, c); // Aligmnent add(alignmentLabel = new Label("Aligmnent:")); c.gridx = 0; c.gridy = 4; c.gridwidth = 1; c.anchor = GridBagConstraints.EAST; gbl.setConstraints(alignmentLabel, c); alignmentControls = new AlignmentControls(axis, axisAlignment); add(alignmentControls); c.gridx = 1; c.gridy = 4; c.gridwidth = GridBagConstraints.REMAINDER; c.anchor = GridBagConstraints.WEST; gbl.setConstraints(alignmentControls, c); // Setup default if(modeControls.cb2D.getState()) { pathControls.setMode2D(); upControls.setMode2D(); drawable.mode(axis, GoText.MODE_2D); } else { pathControls.setMode3D(); upControls.setMode3D(); drawable.mode(axis, GoText.MODE_3D); } } class ModeControls extends Panel implements ItemListener { int axis; CheckboxGroup modeGroup = new CheckboxGroup(); Checkbox cb2D; Checkbox cb3D; ModeControls(int axis, int textMode) { this.axis = axis; add(cb2D = new Checkbox("2D", modeGroup, textMode == GoText.MODE_2D ? true : false)); cb2D.addItemListener(this); add(cb3D = new Checkbox("3D", modeGroup, textMode == GoText.MODE_3D ? true : false)); cb3D.addItemListener(this); } public void itemStateChanged(ItemEvent event) { // // Set text mode (2D or 3D). // Checkbox cb = modeGroup.getSelectedCheckbox(); if(cb == cb2D) { pathControls.setMode2D(); upControls.setMode2D(); drawable.mode(axis, GoText.MODE_2D); rotate.rerender(); } else if(cb == cb3D) { pathControls.setMode3D(); upControls.setMode3D(); drawable.mode(axis, GoText.MODE_3D); rotate.rerender(); } } } class PathControls extends Panel implements FocusListener, ActionListener { int axis; Label xPathLabel, yPathLabel, zPathLabel; TextField xPathField, yPathField, zPathField; PathControls(int axis, double xPath, double yPath, double zPath) { this.axis = axis; add(xPathLabel = new Label("X", Label.RIGHT)); add(xPathField = new TextField(Double.toString(xPath), 5)); xPathField.addFocusListener(this); xPathField.addActionListener(this); add(yPathLabel = new Label("Y", Label.RIGHT)); add(yPathField = new TextField(Double.toString(yPath), 5)); yPathField.addFocusListener(this); yPathField.addActionListener(this); add(zPathLabel = new Label("Z", Label.RIGHT)); add(zPathField = new TextField(Double.toString(zPath), 5)); zPathField.addFocusListener(this); zPathField.addActionListener(this); } public void focusGained(FocusEvent event) { // Do nothing. } public void focusLost(FocusEvent event) { update(); } public void actionPerformed(ActionEvent event) { update(); } void update() { double x = Double.valueOf(xPathField.getText()).doubleValue(); double y = Double.valueOf(yPathField.getText()).doubleValue(); double z = Double.valueOf(zPathField.getText()).doubleValue(); drawable.path(axis, x, y, z); rotate.rerender(); } void setMode2D() { zPathLabel.setEnabled(false); zPathField.setEnabled(false); } void setMode3D() { zPathLabel.setEnabled(true); zPathField.setEnabled(true); } } class UpControls extends Panel implements FocusListener, ActionListener { int axis; Label xUpLabel, yUpLabel, zUpLabel; TextField xUpField, yUpField, zUpField; UpControls(int axis, double xUp, double yUp, double zUp) { this.axis = axis; add(xUpLabel = new Label("X", Label.RIGHT)); add(xUpField = new TextField(Double.toString(xUp), 5)); xUpField.addFocusListener(this); xUpField.addActionListener(this); add(yUpLabel = new Label("Y", Label.RIGHT)); add(yUpField = new TextField(Double.toString(yUp), 5)); yUpField.addFocusListener(this); yUpField.addActionListener(this); add(zUpLabel = new Label("Z", Label.RIGHT)); add(zUpField = new TextField(Double.toString(zUp), 5)); zUpField.addFocusListener(this); zUpField.addActionListener(this); } public void focusGained(FocusEvent event) { // Do nothing. } public void focusLost(FocusEvent event) { update(); } public void actionPerformed(ActionEvent event) { update(); } void update() { double x = Double.valueOf(xUpField.getText()).doubleValue(); double y = Double.valueOf(yUpField.getText()).doubleValue(); double z = Double.valueOf(zUpField.getText()).doubleValue(); drawable.up(axis, x, y, z); rotate.rerender(); } void setMode2D() { upLabel.setEnabled(false); xUpLabel.setEnabled(false); xUpField.setEnabled(false); yUpLabel.setEnabled(false); yUpField.setEnabled(false); zUpLabel.setEnabled(false); zUpField.setEnabled(false); } void setMode3D() { upLabel.setEnabled(true); xUpLabel.setEnabled(true); xUpField.setEnabled(true); yUpLabel.setEnabled(true); yUpField.setEnabled(true); zUpLabel.setEnabled(true); zUpField.setEnabled(true); } } class PositionControls extends Panel { PositionControls(int axis, int axisPosition1, double axisOffset1, int axisPosition2, double axisOffset2) { setLayout(new GridLayout(1, 3)); add(new Position(axis, axisPosition1, axisOffset1, axisPosition2, axisOffset2)); } class Position extends Panel implements ItemListener, FocusListener, ActionListener { int axis; Checkbox axis1Neg; Checkbox axis1Pos; TextField offset1; Checkbox axis2Neg; Checkbox axis2Pos; TextField offset2; CheckboxGroup axisGroup1 = new CheckboxGroup(); CheckboxGroup axisGroup2 = new CheckboxGroup(); Position(int axis, int axisPosition1, double axisOffset1, int axisPosition2, double axisOffset2) { this.axis = axis; setLayout(new GridLayout(2, 2)); switch(axis) { case GoDrawableWithText.X_AXIS: // axis 1 add(axis1Neg = new Checkbox("Y min", axisGroup1, axisPosition1 == GoDrawableWithText.AXIS_MIN ? true : false)); add(axis1Pos = new Checkbox("Y max", axisGroup1, axisPosition1 == GoDrawableWithText.AXIS_MAX ? true : false)); add(new Label("Offset", Label.RIGHT)); add(offset1 = new TextField(Double.toString(axisOffset1), 5)); offset1.addFocusListener(this); offset1.addActionListener(this); // axis 2 add(axis2Neg = new Checkbox("Z min", axisGroup2, axisPosition2 == GoDrawableWithText.AXIS_MIN ? true : false)); add(axis2Pos = new Checkbox("Z max", axisGroup2, axisPosition2 == GoDrawableWithText.AXIS_MAX ? true : false)); add(new Label("Offset", Label.RIGHT)); add(offset2 = new TextField(Double.toString(axisOffset2), 5)); offset2.addFocusListener(this); offset2.addActionListener(this); break; case GoDrawableWithText.Y_AXIS: // axis 1 add(axis1Neg = new Checkbox("X min", axisGroup1, axisPosition1 == GoDrawableWithText.AXIS_MIN ? true : false)); add(axis1Pos = new Checkbox("X max", axisGroup1, axisPosition1 == GoDrawableWithText.AXIS_MAX ? true : false)); add(new Label("Offset", Label.RIGHT)); add(offset1 = new TextField(Double.toString(axisOffset1), 5)); offset1.addFocusListener(this); offset1.addActionListener(this); // axis 2 add(axis2Neg = new Checkbox("Z min", axisGroup2, axisPosition2 == GoDrawableWithText.AXIS_MIN ? true : false)); add(axis2Pos = new Checkbox("Z max", axisGroup2, axisPosition2 == GoDrawableWithText.AXIS_MAX ? true : false)); add(new Label("Offset", Label.RIGHT)); add(offset2 = new TextField(Double.toString(axisOffset2), 5)); offset2.addFocusListener(this); offset2.addActionListener(this); break; case GoDrawableWithText.Z_AXIS: // axis 1 add(axis1Neg = new Checkbox("X min", axisGroup1, axisPosition1 == GoDrawableWithText.AXIS_MIN ? true : false)); add(axis1Pos = new Checkbox("X max", axisGroup1, axisPosition1 == GoDrawableWithText.AXIS_MAX ? true : false)); add(new Label("Offset", Label.RIGHT)); add(offset1 = new TextField(Double.toString(axisOffset1), 5)); offset1.addFocusListener(this); offset1.addActionListener(this); //axis 2 add(axis2Neg = new Checkbox("Y min", axisGroup2, axisPosition2 == GoDrawableWithText.AXIS_MIN ? true : false)); add(axis2Pos = new Checkbox("Y max", axisGroup2, axisPosition2 == GoDrawableWithText.AXIS_MAX ? true : false)); add(new Label("Offset", Label.RIGHT)); add(offset2 = new TextField(Double.toString(axisOffset2), 5)); offset2.addFocusListener(this); offset2.addActionListener(this); break; } axis1Neg.addItemListener(this); axis1Pos.addItemListener(this); axis2Neg.addItemListener(this); axis2Pos.addItemListener(this); } public void itemStateChanged(ItemEvent event) { update(); } public void focusGained(FocusEvent event) { // Do nothing. } public void focusLost(FocusEvent event) { update(); } public void actionPerformed(ActionEvent event) { update(); } void update() { int axis1 = axis1Neg.getState() ? GoDrawableWithText.AXIS_MIN : GoDrawableWithText.AXIS_MAX; double offset1Val = Double.valueOf(offset1.getText()).doubleValue(); int axis2 = axis2Neg.getState() ? GoDrawableWithText.AXIS_MIN : GoDrawableWithText.AXIS_MAX; double offset2Val = Double.valueOf(offset2.getText()).doubleValue(); drawable.position(axis, axis1, offset1Val, axis2, offset2Val); rotate.rerender(); } } } class AlignmentControls extends Panel { AlignmentControls(int axis, int axisAlignment) { setLayout(new GridLayout(1, 2)); add(new Alignment(axis, axisAlignment)); } class Alignment extends Panel implements ItemListener { int axis; CheckboxGroup alignmentGroup = new CheckboxGroup(); Checkbox leftTop; Checkbox centerTop; Checkbox rightTop; Checkbox leftCenter; Checkbox centerCenter; Checkbox rightCenter; Checkbox leftBottom; Checkbox centerBottom; Checkbox rightBottom; Alignment(int axis, int axisAlignment) { this.axis = axis; setLayout(new GridLayout(3, 3)); add(leftTop = new Checkbox("", alignmentGroup, axisAlignment == GoText.LEFT_TOP ? true : false)); leftTop.addItemListener(this); add(centerTop = new Checkbox("", alignmentGroup, axisAlignment == GoText.CENTER_TOP ? true : false)); centerTop.addItemListener(this); add(rightTop = new Checkbox("", alignmentGroup, axisAlignment == GoText.RIGHT_TOP ? true : false)); rightTop.addItemListener(this); add(leftCenter = new Checkbox("", alignmentGroup, axisAlignment == GoText.LEFT_CENTER ? true : false)); leftCenter.addItemListener(this); add(centerCenter = new Checkbox("", alignmentGroup, axisAlignment == GoText.CENTER_CENTER ? true : false)); centerCenter.addItemListener(this); add(rightCenter = new Checkbox("", alignmentGroup, axisAlignment == GoText.RIGHT_CENTER ? true : false)); rightCenter.addItemListener(this); add(leftBottom = new Checkbox("", alignmentGroup, axisAlignment == GoText.LEFT_BOTTOM ? true : false)); leftBottom.addItemListener(this); add(centerBottom = new Checkbox("", alignmentGroup, axisAlignment == GoText.CENTER_BOTTOM ? true : false)); centerBottom.addItemListener(this); add(rightBottom = new Checkbox("", alignmentGroup, axisAlignment == GoText.RIGHT_BOTTOM ? true : false)); rightBottom.addItemListener(this); } public void itemStateChanged(ItemEvent event) { Checkbox cb = alignmentGroup.getSelectedCheckbox(); if(cb == leftTop) { drawable.alignment(axis, GoText.LEFT_TOP); rotate.rerender(); } else if(cb == centerTop) { drawable.alignment(axis, GoText.CENTER_TOP); rotate.rerender(); } else if(cb == rightTop) { drawable.alignment(axis, GoText.RIGHT_TOP); rotate.rerender(); } else if(cb == leftCenter) { drawable.alignment(axis, GoText.LEFT_CENTER); rotate.rerender(); } else if(cb == centerCenter) { drawable.alignment(axis, GoText.CENTER_CENTER); rotate.rerender(); } else if(cb == rightCenter) { drawable.alignment(axis, GoText.RIGHT_CENTER); rotate.rerender(); } else if(cb == leftBottom) { drawable.alignment(axis, GoText.LEFT_BOTTOM); rotate.rerender(); } else if(cb == centerBottom) { drawable.alignment(axis, GoText.CENTER_BOTTOM); rotate.rerender(); } else if(cb == rightBottom) { drawable.alignment(axis, GoText.RIGHT_BOTTOM); rotate.rerender(); } } } } } } public class rotateWithText extends Applet { GoRotateWithTextPanel panel; Go go; public void init() { // // Fonts will be found relative to the html document // that includes this applet. // GoFont.path(getDocumentBase()); // // Setup a GoRotatePanel. // setLayout(new GridLayout(1, 1)); add(panel = new GoRotateWithTextPanel()); // // Get the Go context. // go = panel.rotate.go; // // Create the function to be displayed. // FunctionWithText function = new FunctionWithText( // // Context // go, // // Function range & resolution // -3.0, 3.0, // X range -3.0, 3.0, // Y range -1.0, 1.0, // Z range 8, 8, // X-Y fish-net resolution // // X-axis text values that work with initial view. // -3.0, // min text value 3.0, // max text value 4, // text value divisions GoText.MODE_3D, // text mode 0.0, 1.0, 0.0, // path vector 0.0, 0.0, 1.0, // up vector GoDrawableWithText.AXIS_MIN, // Y-axis position 0.3, // Y-axis offset GoDrawableWithText.AXIS_MIN, // Z-axis position 0.0, // Z-axis offset GoText.RIGHT_CENTER, // alignment // // Y-axis text values that work with initial view. // -3.0, // min text value 3.0, // max text value 4, // text value divisions GoText.MODE_3D, // text mode 1.0, 0.0, 0.0, // path vector 0.0, 0.0, 1.0, // up vector GoDrawableWithText.AXIS_MAX, // X-axis position 0.3, // X-axis offset GoDrawableWithText.AXIS_MIN, // Z-axis position 0.0, // Z-axis offset GoText.LEFT_CENTER, // alignment // // Z-axis text values that work with initial view. // -1.0, // min text value 1.0, // max text value 2, // text value divisions GoText.MODE_3D, // text mode 1.0, 0.0, 0.0, // path vector 0.0, 0.0, 1.0, // up vector GoDrawableWithText.AXIS_MIN, // X-axis position 0.3, // X-axis offset GoDrawableWithText.AXIS_MIN, // Y-axis position 0.0, // Y-axis offset GoText.RIGHT_CENTER // alignment ); // // Setup a light. // go.light(go.LIGHT_0, true); go.light(go.LIGHT_0, go.DIRECTIONAL, -1.3, 2.4, 1.0); // // Define the initial view. // double eyeMult = 3.0; double eyeX = 1.3 * eyeMult; double eyeY = -1.5 * eyeMult; double eyeZ = 1.5 * eyeMult; double centerX = (function.xMinTotal + function.xMaxTotal) / 2.0; double centerY = (function.yMinTotal + function.yMaxTotal) / 2.0; double centerZ = (function.zMinTotal + function.zMaxTotal) / 2.0; double upX = 0.0; double upY = 0.0; double upZ = 1.0; double radius = distance(centerX, centerY, centerZ, function.xMaxTotal, function.yMaxTotal, function.zMaxTotal); boolean perspective = false; // // Setup the rotate panel. // panel.setup(function, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, radius, perspective); } // // Calculate distance between two points. // double distance(double x0, double y0, double z0, double x1, double y1, double z1) { double dx = x1 - x0; double dy = y1 - y0; double dz = z1 - z0; return Math.sqrt(dx*dx + dy*dy + dz*dz); } }