import java.awt.*; /** * A class which creates and manipulates the isometric or equidistant * circles which make the up the fundamental domain on the boundary of * hyperbolic space. * * @author Jonathan A. Poritz * @version 1.7, 17 Sep 1998 */ public class BoundaryCircle { /** * The minimum x-coord, in pixels, of a BoundaryCircle we will display. * Probably should be a related to X in BoundaryCircle. */ public static final int MINDISPLAY_X = -1000; /** * The maximum x-coord, in pixels, of a BoundaryCircle we will display. * Probably should be a related to X in BoundaryCircle. */ public static final int MAXDISPLAY_X = 1300; /** * The minimum y-coord, in pixels, of a BoundaryCircle we will display. * Probably should be a related to X in BoundaryCircle. */ public static final int MINDISPLAY_Y = -1000; /** * The maximum y-coord, in pixels, of a BoundaryCircle we will display. * Probably should be a related to X in BoundaryCircle. */ public static final int MAXDISPLAY_Y = 1300; /** * The complex location of the center of the isometric or * equidistant circle. */ Complex cen; /** * The radius of the isometric or equidistant circle. */ double rad; /** * The index of the isometric or equidistant circle. */ int index; /** * Constructor for BoundaryCircles of elliptic or loxodromic traces. * * @param z11 the (1,1) entry of the current trace's generator matrix * @param dist the current axis distance * @param ndx the index of this BoundaryCircle * @param domaintype the selected index of outputpanel's * Choice fordordirichlet */ public BoundaryCircle(Complex z11, double dist, int ndx, int domaintype) { // save the index index = ndx; // compute the center and radius if (domaintype == 0) { // a Ford domain Complex z11sq = Complex.square(z11); Complex z11sqmno = Complex.subtract(z11sq, Complex.ONE); cen = Complex.divide(z11sq, z11sqmno); rad = Complex.modulus(Complex.divide(z11, z11sqmno)); } else { // a Dirichlet domain double fourtsq = Math.exp(2D*dist); Complex z11inv = Complex.divide(Complex.ONE, z11); Complex z11plz11inv = Complex.add(z11, z11inv); Complex z11mnz11inv = Complex.subtract(z11, z11inv); Complex partnumer = Complex.multiply(z11, Complex.conj(Complex.add(z11plz11inv, Complex.multiply(z11mnz11inv, new Complex(fourtsq, 0D))))); double partdenom = Complex.modsq(z11plz11inv) + Complex.modsq(z11mnz11inv) * fourtsq; double partdenommn4 = partdenom - 4D; cen = Complex.divide(Complex.subtract(partnumer, Complex.TWO), new Complex(partdenommn4, 0D)); rad = Math.sqrt((fourtsq / partdenom) * (1D + Complex.modsq(Complex.subtract(Complex.multiply(Complex.TWO, partnumer), new Complex(partdenom, 0D))) / (fourtsq * partdenommn4 * partdenommn4))); } } /** * Constructor for BoundaryCircles of parabolic traces. * * @param ndx the index of this BoundaryCircle */ public BoundaryCircle(int ndx) { // save the index, compute the center and radius index = ndx; cen = new Complex((1D/((double) ndx)), 0D); rad = 1D/Math.abs((double) ndx); } /** * Constructor of a trivial BoundaryCircle. */ public BoundaryCircle() { cen = new Complex(); rad = 0D; index = 0; } /** * Paint this BoundaryCircle if it is not too huge, paying attention to the * currently selected display type. * * @param g the graphics object upon which to paint * @param boundarypanel the ambient BoundaryPanel * @param diskorcircle a reference to outputpanel's choice on the * selected display type */ public void paint(Graphics g, BoundaryPanel boundarypanel, Choice diskorcircle) { // compute the coordinates of the upper-left and lower-right corners of // a box enclosing this BoundaryCircle int ulcorner[] = boundarypanel.abstractToPixels(cen.x - rad, cen.y + rad); int lrcorner[] = boundarypanel.abstractToPixels(cen.x + rad, cen.y - rad); // don't display at all if this BoundaryCircle is too bid if ((ulcorner[0] < MINDISPLAY_X) || (ulcorner[1] > MAXDISPLAY_X) || (lrcorner[0] < MINDISPLAY_X) || (lrcorner[1] > MAXDISPLAY_X)) return; // what index is chosen for the display type choice int dcselindx = diskorcircle.getSelectedIndex(); if (dcselindx == 0) { // display disks g.fillOval(ulcorner[0], ulcorner[1], lrcorner[0] - ulcorner[0], lrcorner[1] - ulcorner[1]); return; } // otherwise, show circles g.drawOval(ulcorner[0], ulcorner[1], lrcorner[0] - ulcorner[0], lrcorner[1] - ulcorner[1]); if (dcselindx == 1) { // but return if we are not to display indices return; } // show indices g.setFont(new Font("courier", Font.PLAIN, 10)); if (Math.abs(cen.y + rad) > Math.abs(cen.y - rad)) { int top[] = boundarypanel.abstractToPixels(cen.x, cen.y + rad); g.drawString(Integer.toString(index), top[0] - 3, top[1]); } else { int bottom[] = boundarypanel.abstractToPixels(cen.x, cen.y - rad); g.drawString(Integer.toString(index), bottom[0] - 3, bottom[1] + 8); } return; } /** * Compute the distance between the centers of two BoundaryCircles. * * @param a one BoundaryCircle * @param b and another * @return the distance between their centers */ public static double distance(BoundaryCircle a, BoundaryCircle b) { return Math.sqrt(Complex.distsq(a.cen, b.cen)); } /** * Copies this BoundaryCircle, by making a trivial BoundaryCircle and * then copying into it this's center, radius and index. * * @return the new copy of this BounaryCircle */ public BoundaryCircle copyCircle() { BoundaryCircle x = new BoundaryCircle(); x.cen.x = this.cen.x; x.cen.y = this.cen.y; x.rad = this.rad; x.index = this.index; return x; } /** * Makes a negative BoundaryCircle corresponding to the input of a * positive one. * * @param pos the positive BoundaryCircle to be copied and negated * @returns the new negative BoundaryCircle */ public static BoundaryCircle makeNeg(BoundaryCircle pos) { // copy the input BoundaryCircle BoundaryCircle neg = pos.copyCircle(); // make the index negative and take one minus the center neg.index = -pos.index; neg.cen = Complex.subtract(Complex.ONE, pos.cen); return neg; } /** * Make a string out of this's index. Only called implicitly when making * a label for fundamental domain of impossible combinatorial type, by * Vector.toString on DomainCombinatorics's Vector * boundary. * * @return the string form of this's index */ public String toString() { return Integer.toString(index); } }