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);
}
}