import java.awt.*; /** * A class which shows the fundamental domain corresponding to the current * trace value and display parameters, on a portion of the boundary of * hyperbolic space. * * @author Jonathan A. Poritz * @version 1.7, 10 Sep 1998 */ public class BoundaryPanel extends Plane { /** * The (1,1) entry of the element cannonically associated with the current * trace. */ public Complex z11 = new Complex(); /** * The currently selected axis distance. */ public double dist; /** * A reference to the label in outputpanel declaring the portion of * the boundary of hyperbolic space which is currently visible. * * @see OutputPanel#boundarypanellabel */ public Label boundarypanellabel; /** * The maxpow calculated for a Ford domain with the current trace -- not * necessarily valid for a Dirichlet domain with the same trace, but used * nonetheless. */ public int calcmaxpow; /** * The overriding maxpow chosen by the user if so desired taken from * maxpowchoice. */ public int chosenmaxpow; /** * A boolean telling if we should use the calcmaxpow or some other * choice, to be found in chosenmaxpow. */ public boolean usecalcmaxpow; /** * A reference to the choice in outputpanel of displaying disks, * circles or circle with labeling indices. * * @see OutputPanel#diskorcircle */ public Choice diskorcircle; /** * A reference to the choice in outputpanel of computing Ford or * Dirichlet domains. * * @see OutputPanel#fordordirichlet */ public Choice fordordirichlet; /** * An array of BoundaryCircles with positive indices. */ protected BoundaryCircle pc[] = null; /** * An array of BoundaryCircles with negative indices. */ protected BoundaryCircle nc[] = null; /** * The location of a mousedown in this plane, to compute the extent of * a drag that may occur; in abstract coordinates. */ protected double[] prev = new double[2]; /** * The location of a mousedown in this plane, to compute the extent of * a drag that may occur; in pixel coordinates. */ protected int[] previ = new int[2]; /** * The abstract x-coordinate of the left side of the boundary plane display. */ public static final double CX = -1.5D; /** * The abstract y-coordinate of the upper edge of the boundary plane display. */ public static final double CY = 2D; /** * The width, in abstract units, of the boundary plane display. */ public static final double SX = 4D; /** * The height, in abstract units, of the boundary plane display. */ public static final double SY = 4D; /** * The width, in pixels, of the boundary plane display. Good defaults are: * */ public static final int X = 300; /** * The height, in pixels, of the boundary plane display. Good defaults are: * */ public static final int Y = 300; /** * Constructor for BoundaryPanels. * * @param bdrypnllbl the label describing the current window on the boundary * plane * @param dskrcrcl the choice of display styles of the isometric or * equidistant circles * @param frdrdrchlt the choice of making Ford or Dirichlet domains. */ public BoundaryPanel(Label bdrypnllbl, Choice dskrcrcl, Choice frdrdrchlt) { // creat the ambient plane, with axes and xticks shown super(CX, CY, SX, SY, X, Y); draw_axes = true; show_xticks = true; // we start using the calculated maxpows usecalcmaxpow = true; // save the references to the boundary panel label, disk or circle choice // and Ford or Dirichlet domain choice boundarypanellabel = bdrypnllbl; diskorcircle = dskrcrcl; fordordirichlet = frdrdrchlt; // set the boundary panel label correctly boundarypanellabel.setText(this.toString()); } /** * Java 1.0 handling of mouseDown events. * * @param e the event to be handled * @param x the x-coordinate (in pixels) of the mouseDown * @param y the y-coordinate (in pixels) of the mouseDown */ public boolean mouseDown(Event e, int x, int y) { // always save pixel location of mouseDown previ[0] = x; previ[1] = y; if ((e.modifiers & e.META_MASK) != 0) { // right button zoom, all we needed was to save location of mouseDown, // can now return return true; } // left or middle button translate, save abstract coordinates as well prev[0] = (pixelsToAbstract(x, y))[0]; prev[1] = (pixelsToAbstract(x, y))[1]; return true; } /** * Java 1.0 handling of mouseDrag events. * * @param e the event to be handled * @param x the x-coordinate (in pixels) of the mouseDrag * @param y the y-coordinate (in pixels) of the mouseDrag */ public boolean mouseDrag(Event e, int x, int y) { // convert to abstract coordinates double xx = (pixelsToAbstract(x, y))[0]; double yy = (pixelsToAbstract(x, y))[1]; if ((e.modifiers & e.META_MASK) != 0) { // right button zoom zoom(1D - ((double)(previ[1] - y)) / 50D); } else { // left or middle mouse translate corner[0] += prev[0] - xx; corner[1] += prev[1] - yy; boundarypanellabel.setText(this.toString()); repaint(); } previ[0] = x; previ[1] = y; return true; } /** * Paint the BoundaryPanel by painting the basic plane, calling the paint * on each of the current negative and positive BoundaryCircles, then * drawing the tickmarks. * * @param g the Graphics object upon which to paint the TracePlanePanel */ public synchronized void paint(Graphics g) { // paint the basic plane super.paint(g); // paint the positive and negative BoundaryCircles, in a rainbow of // colors, up to the maxpow in use at the moment int max = usecalcmaxpow ? calcmaxpow : chosenmaxpow; for (int i=0; i < max; i++) { int j = 255*i/max; g.setColor(new Color(j,0,j)); pc[i].paint(g, this, diskorcircle); g.setColor(new Color(0,j,255-j)); nc[i].paint(g, this, diskorcircle); } drawTickmarks(g); } /** * Scales the size of the visible window onto the boundary of * hyperbolic space. * * @param factor the scaling factor, can be any positive number */ public void zoom(double factor) { corner[0] = corner[0] + .5D * size[0] - .5D * size[0] * factor; size[0] *= factor; corner[1] = corner[1] - .5D * size[1] + .5D * size[1] * factor; size[1] *= factor; boundarypanellabel.setText(this.toString()); repaint(); } /** * Recreates the current positive and negative BoundaryCircles and then * repaints, called when some relevant parameter has changed. */ public synchronized void update() { // make a arrays of positive and negative BoundaryCircles // of the appropriate length int max = usecalcmaxpow ? calcmaxpow : chosenmaxpow; pc = new BoundaryCircle[max]; nc = new BoundaryCircle[max]; if ((z11.y == 0D) && ((z11.x == 1D) || (z11.x == -1D))) { // parabolic generator, call the appropriate BoundaryCircle constructor for (int i=0; i < max; i++) { pc[i] = new BoundaryCircle(i+1); nc[i] = new BoundaryCircle(-i-1); } } else { // elliptic or loxodromic generator int domaintype = fordordirichlet.getSelectedIndex(); Complex z11powers = new Complex(Complex.ONE); for (int i=0; i < max; i++) { // take the power of the generator z11powers = Complex.multiply(z11powers, z11); // make a positive BoundaryCircle with the right constructor, // then make a negative version of it BoundaryCircle poscirc = new BoundaryCircle(z11powers, dist, i+1, domaintype); pc[i] = poscirc; nc[i] = BoundaryCircle.makeNeg(poscirc); } } repaint(); } }