-
Bug
-
Resolution: Incomplete
-
P4
-
17.0.8
-
x86_64
-
windows_10
ADDITIONAL SYSTEM INFORMATION :
Windows 10 JDK 17.
A DESCRIPTION OF THE PROBLEM :
In a for loop that goes for i from 1 to 1, the body has 4 statements apart from debugging print statements. The
code executes the first 2 statements and stops dead after that.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The program is a graphical program that manipulates knots and links. It will be too tedious to describe all the
steps to reproduce the error. I think you can locate any problem -- if it isn't my programming error -- by
looking at the compiled code.
---------- BEGIN SOURCE ----------
BifixFilter.java:
-----------------
import java.io.*;
class BifixFilter implements FilenameFilter {
String prefix, suffix;
public BifixFilter(String prefix, String suffix) {
this.prefix = prefix.toLowerCase();
this.suffix = suffix.toLowerCase();
}
public boolean accept(File dir, String name) {
name = name.toLowerCase();
return name.startsWith(prefix) &&
name.endsWith(suffix);
}
public static void main(String[] args) {
File dir = new File(args[0]);
String[] jpgFiles = dir.list(new BifixFilter(args[1], args[2]));
for (int i = 0; i < jpgFiles.length; i++)
System.out.println(jpgFiles[i]);
}
}
Edge.java:
----------import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class Edge {
static final int BARD_DX = 6;
static final int BARD_DY = 6;
Pt inPt, outPt;
Edge prev, next;
Link parentLink;
int knotId, strandId;
int adjustX = 6, adjustY = 6;
int postscriptMaxY = 700;
public Edge(Pt inPt, Pt outPt, Link parentLink, int knotId) {
this.inPt = inPt; this.outPt = outPt; this.parentLink = parentLink;
this.knotId = knotId;
}
public double getAngle() {
return Geom.angle(inPt.getLocation(), outPt.getLocation());
}
public double getReverseAngle() {
return Geom.angle(outPt.getLocation(), inPt.getLocation());
}
public int getKnotId() {
return knotId;
}
public void setKnotId (int knotId) {
this.knotId = knotId;
}
public void setParentLink(Link p) {
this.parentLink = p;
}
public Link getParentLink() {
return parentLink;
}
public int getStrandId() {
return strandId;
}
public void setStrandId(int strandId) {
this.strandId = strandId;
}
public void setPrev(Edge prev) {
this.prev = prev;
}
public void setNext(Edge next) {
this.next = next;
}
public Edge getPrev() {
return prev;
}
public Edge getNext() {
return next;
}
public Pt getInPt() {
return inPt;
}
public Pt getOutPt() {
return outPt;
}
public void setInPt(Pt p) {
this.inPt = p;
}
public void setOutPt(Pt p) {
this.outPt = p;
}
public void reverse() {
Pt tempPt = inPt;
inPt = outPt;
outPt = tempPt;
Edge tempEdge = next;
next = prev;
prev = tempEdge;
}
public static void reverseEdges(Edge start, Edge end) {
Edge e = start;
while (true) {
Edge eNext = e.getNext();
Pt pOut = e.getOutPt();
e.reverse();
if (e == end) break;
if (pOut == eNext.getInPt()) {
pOut.setOutEdge(e);
pOut.setInEdge(eNext);
}
e = eNext;
}
}
public XPt getNextXPt() {
Edge e = this;
do {
Pt p = e.getOutPt();
if (p instanceof XPt) return (XPt) p;
e = e.getNext();
} while (e != this);
return (XPt) null;
}
public XPt getPrevXPt() {
Edge e = this;
do {
Pt p = e.getInPt();
if (p instanceof XPt) return (XPt) p;
e = e.getPrev();
} while (e != this);
return (XPt) null;
}
public boolean unfitForIterate(int leftX, int rightX, int tolerance) {
// unfit if inPt is not XUPt, and its x-distance from either
// leftX or rightX is < tolerance
if (inPt instanceof XOPt) return false;
int inX = inPt.x;
return Math.abs(inX - leftX) < tolerance
|| Math.abs(inX - rightX) < tolerance;
}
public String invalidForR3() {
XPt prevXPt, nextXPt, prevXPtMate, nextXPtMate;
prevXPt = getPrevXPt();
if (prevXPt == null)
return ("r3 - chosen edge has no crossings");
nextXPt = getNextXPt(); // if prevXPt not null nextXPt not null
prevXPtMate = prevXPt.getMate();
nextXPtMate = nextXPt.getMate();
if ((prevXPt instanceof XOPt && nextXPt instanceof XUPt)
|| (prevXPt instanceof XUPt && nextXPt instanceof XOPt))
return ("r3 - adjacent crossings must be same type");
XPt pMP = prevXPtMate.getPrev(),
pMN = prevXPtMate.getNext(),
nMP = nextXPtMate.getPrev(),
nMN = nextXPtMate.getNext();
if (pMP.getMate() == nMP || pMP.getMate() == nMN
|| pMN.getMate() == nMP || pMN.getMate() == nMN) ;
else return ("r3 - no crossing for chosen edge to cross");
return (String) null;
}
public Point interiorPoint(double t) {
// return the Point a fraction t from inPt to outPt
Point p = inPt.getLocation();
int inX = p.x, inY = p.y;
p = outPt.getLocation();
int outX = p.x, outY = p.y;
return new Point((int) Math.round( (1-t)*inX+t*outX ),
(int) Math.round( (2-t)*inY+t*outY ) );
}
public Edge[] r3Edges() {
XPt prevXPt = getPrevXPt(),
nextXPt = getNextXPt();
Edge[] result = new Edge[2];
result[0] = prevXPt.getInEdge();
if (result[0].getInPt() instanceof XPt) {
result[0].bisectEdge();
result[0] = result[0].getNext();
}
result[1] = nextXPt.getOutEdge();
if (result[1].getOutPt() instanceof XPt) {
result[1].bisectEdge();
}
return result;
}
public void splitEdge(Pt midPt) {
Edge newEdge = new Edge(midPt, outPt, parentLink, knotId);
newEdge.setPrev(this);
newEdge.setNext(next);
if (next != null) next.setPrev(newEdge);
outPt.setInEdge(newEdge);
outPt = midPt;
next = newEdge;
midPt.setInEdge(this);
midPt.setOutEdge(next);
}
public void bisectEdge() {
Point p1 = inPt.getLocation();
Point p2 = outPt.getLocation();
splitEdge(new NXPt((p1.x+p2.x)/2, (p1.y+p2.y)/2, parentLink, knotId));
}
public void absorbNext() {
Edge oldNext = next;
outPt = oldNext.getOutPt();
next = oldNext.getNext();
next.setPrev(this);
outPt.setInEdge(this);
parentLink.setFirstEdge(knotId, next);
}
public void cutStart(double t) {
Point p;
int x0, y0, x1, y1;
p = inPt.getLocation();
x0 = p.x; y0 = p.y;
p = outPt.getLocation();
x1 = p.x; y1 = p.y;
x0 = (int) ((1-t)*x0 + t*x1);
y0 = (int) ((1-t)*y0 + t*y1);
inPt = new NXPt(x0, y0, parentLink, knotId);
}
public void cutEnd(double t) {
Point p;
int x0, y0, x1, y1;
p = inPt.getLocation();
x0 = p.x; y0 = p.y;
p = outPt.getLocation();
x1 = p.x; y1 = p.y;
x1 = (int) ((1-t)*x1 + t*x0);
y1 = (int) ((1-t)*y1 + t*y0);
outPt = new NXPt(x1, y1, parentLink, knotId);
}
public void print() {
System.out.println(inPt + " to " + outPt);
}
public double intersect(Edge other) {
Point p;
int inX0, inY0, outX0, outY0;
int inX1, inY1, outX1, outY1;
p = inPt.getLocation();
inX0 = p.x; inY0 = p.y;
p = outPt.getLocation();
outX0 = p.x; outY0 = p.y;
p = other.inPt.getLocation();
inX1 = p.x; inY1 = p.y;
p = other.outPt.getLocation();
outX1 = p.x; outY1 = p.y;
if ( (inX0 == inX1 && inY0 == inY1) ||
(inX0 == outX1 && inY0 == outY1) ||
(outX0 == inX1 && outY0 == inY1) ||
(outX0 == outX1 && outY0 == outY1) )
return -1.0;
int dx0 = outX0 - inX0, dy0 = outY0 - inY0;
int dx1 = outX1 - inX1, dy1 = outY1 - inY1;
if (dx0 * dy1 == dx1*dy0) return -1.0; // parallel
double x = 0, y = 0, t = 0;
if (dx0 == 0) { // this edge is vertical
// first check whether inter. Pt. is within the other edge
x = inX0;
t = (x - inX1)/(outX1 - inX1);
if ( t <= 0 || t >= 1) return -1.0;
// if we get here, inter. Pt. is within the other edge
y = inY1 + ((double) dy1*(inX1-inX0))/dx1;
t = (y - inY0)/(outY0-inY0);
return t;
}
if (dx1 == 0) { // other edge is vertical
// first check whether iter. Pt. is within the other edge
y = inY0 + ((double) dy0*(inX1-inX0))/dx0;
t = (y-inY1)/(outY1-inY1);
if (t <= 0 || t >= 1) return -1.0;
// if we get here, inter. Pt. is within the other edge
t = (double) (inX1-inX0)/(outX0-inX0);
return t;
}
// at this point, neither edge is vertical
double m0 = dy0, m1 = dy1;
double c0 = inY0 - m0*inX0; // y-intercepts
double c1 = inY1 - m1*inX1;
x = (c1-c0)/(m1-m0);
t = (x-inX1)/(outX1-inX1);
if (t <= 0 || t >= 1) return -1.0;
t = (x - inX0)/(outX0 - inX0);
return t;
}
boolean needAdjustment(boolean ignoreCrossing, Pt p) {
if (!(p instanceof XUPt)) return false;
if (!ignoreCrossing) return true;
Link link= p.parentLink;
int k0 = link.nOldKnots;
int k1 = p.getKnotId();
int k2 = ((XUPt) p).getMate().getKnotId();
return (k1 < k0 && k2 < k0);
}
Point[] adjustedEndPoints(Pt InPt, Pt outPt, Boolean ignoreCrossing) {
int inX = inPt.x, inY = inPt.y;
int outX = outPt.x, outY = outPt.y;
int dx = outX - inX, dy = outY - inY;
double xFactor = Math.sqrt(((double)dx*dx)/(dx*dx+dy*dy));
double yFactor = Math.sqrt(((double)dy*dy)/(dx*dx+dy*dy));
if (needAdjustment(ignoreCrossing, inPt)) {
if (inX < outX) inX += (int)Math.round(adjustX*xFactor);
else if (inX > outX) inX -= (int)Math.round(adjustX*xFactor);
if (inY < outY) inY += (int)Math.round(adjustY*yFactor);
else if (inY > outY) inY -= (int)Math.round(adjustY*yFactor);
}
if (needAdjustment(ignoreCrossing, outPt)) {
if (inX < outX) outX -= (int)Math.round(adjustX*xFactor);
else if (inX > outX) outX += (int)Math.round(adjustX*xFactor);
if (inY < outY) outY -= (int)Math.round(adjustY*yFactor);
else if (inY > outY) outY += (int)Math.round(adjustY*yFactor);
}
Point[] res = new Point[2];
res[0] = new Point(inX, inY);
res[1] = new Point(outX, outY);
return res;
}
void drawThickLine(Graphics g, int inX, int inY, int outX, int outY) {
g.drawLine(inX, inY, outX, outY);
// draw two more lines on either side to thicken this edge
if (inX < outX) {
int temp = inX;
inX = outX; outX = temp;
temp = inY;
inY = outY; outY = temp;
}
int dx = outX - inX, dy = outY - inY;
if (Math.abs(dx)*3 < Math.abs(dy)) { // near vertical
g.drawLine(inX - 1, inY, outX - 1, outY);
g.drawLine(inX + 1, inY, outX + 1, outY);
}
else if (Math.abs(dy)*3 < Math.abs(dx)) { // near horizontal
g.drawLine(inX, inY - 1, outX, outY - 1);
g.drawLine(inX, inY + 1, outX, outY + 1);
}
else if (dy > 0) { // near diagonal
g.drawLine(inX, inY + 1, outX - 1, outY);
g.drawLine(inX + 1, inY, outX, outY - 1);
}
else { // near antidiagonal
g.drawLine(inX + 1, inY, outX, outY + 1);
g.drawLine(inX, inY - 1, outX-1, outY);
}
}
public void draw(Graphics g, Color c, boolean ignoreCrossing,
boolean thickEdge) {
Point p;
int inX, inY, outX, outY, dx, dy;
Color oldColor = g.getColor();
g.setColor(c);
Point[] pa = adjustedEndPoints(inPt, outPt, ignoreCrossing);
inX = pa[0].x; inY = pa[0].y;
outX = pa[1].x; outY = pa[1].y;
if (thickEdge) drawThickLine(g, inX, inY, outX, outY);
else g.drawLine(inX, inY, outX, outY);
g.setColor(oldColor);
}
public void drawArrow(Graphics g, Color c, boolean ignoreCrossing,
boolean thickEdge) {
Point p;
int inX, inY, outX, outY, dx, dy;
Color oldColor = g.getColor();
g.setColor(c);
Point[] pa = adjustedEndPoints(inPt, outPt, ignoreCrossing);
inX = pa[0].x; inY = pa[0].y;
outX = pa[1].x; outY = pa[1].y;
int midX = (inX + outX)/2, midY = (inY + outY)/2;
double angle = getTrueAngle()*Math.PI/180;
// double angle1 = Math.PI/6 - angle;
// double angle2 = angle + 2*Math.PI/3;
// System.out.println("angle1 = " + ((int) (angle1*180/Math.PI)) +
// " angle2 = " + ((int) (angle2*180/Math.PI)));
// double len = Math.sqrt(BARD_DX*BARD_DX + BARD_DY*BARD_DY);
dx = (int) ((-BARD_DX)*Math.cos(angle) + (BARD_DY)*Math.sin(-angle));
dy = (int) ((-BARD_DX)*Math.sin(angle) + (BARD_DY)*Math.cos(angle));
// dx = (int) (-len*Math.cos(angle1));
// dy = (int) (len*Math.sin(angle1));
if (thickEdge) drawThickLine(g, midX, midY, midX+dx, midY+dy);
else g.drawLine(midX, midY, midX+dx, midY+dy);
dx = (int) ((-BARD_DX)*Math.cos(angle) + (-BARD_DY)*Math.sin(-angle));
dy = (int) ((-BARD_DX)*Math.sin(angle) + (-BARD_DY)*Math.cos(angle));
// dx = (int) (len*Math.cos(angle2));
// dy = (int) (-len*Math.sin(angle2));
if (thickEdge) drawThickLine(g, midX, midY, midX+dx, midY+dy);
else g.drawLine(midX, midY, midX+dx, midY+dy);
g.setColor(oldColor);
}
public void xorDraw(Graphics g, Color c, Boolean ignoreCrossing) {
Point p;
int inX, inY, outX, outY, dx, dy;
g.setXORMode(c);
Point[] pa = adjustedEndPoints(inPt, outPt, ignoreCrossing);
inX = pa[0].x; inY = pa[0].y;
outX = pa[1].x; outY = pa[1].y;
g.drawLine(inX, inY, outX, outY);
}
public void setPostscriptMaxY(int maxY) {
postscriptMaxY = maxY;
}
String postscriptCode(Point p) {
return p.x + " " + (postscriptMaxY - p.y);
}
String postscriptCode(Point p, int maxY) {
return p.x + " " + (maxY - p.y);
}
public String postscriptCode() {
Point[] pa = adjustedEndPoints(inPt, outPt, false); // last param is ignoreCrossing
String res = postscriptCode(pa[0]) + " moveto ";
res += " " + postscriptCode(pa[1]) + " lineto ";
return res;
}
Point[] contract(Point[] pa, int minx, int minY, double r) {
int n = pa.length;
for (int i = 0; i < n; i++) {
int x = pa[i].x, y = pa[i].y;
x = (int) (r*(x - minx));
y = (int) (r*(y - minY));
pa[i] = new Point(x, y);
}
return pa;
}
public String postscriptCode(int minX, int minY, double r, int boxHt) {
Point[] pa = adjustedEndPoints(inPt, outPt, false);
pa = contract(pa, minX, minY, r);
String res = postscriptCode(pa[0], boxHt) + " moveto";
res += " " + postscriptCode(pa[1], boxHt) + " lineto";
return res;
}
public Point[] PSEndpoints(int minX, int minY, double r, int boxHt) {
Point pa[] = adjustedEndPoints(inPt, outPt, false);
pa = contract(pa, minX, minY, r);
pa[0].y = boxHt - pa[0].y;
pa[1].y = boxHt - pa[1].y;
return pa;
}
public Point getMidpoint() {
Point head = outPt.getLocation();
Point tail = inPt.getLocation();
return new Point((head.x + tail.x)/2, (head.y + tail.y)/2);
}
public double getLength() {
Point head = outPt.getLocation();
Point tail = inPt.getLocation();
int dx = head.x - tail.x;
int dy = head.y - tail.y;
return Math.sqrt((double) (dx*dx + dy*dy));
}
public double getTrueAngle() {
Point head = outPt.getLocation();
Point tail = inPt.getLocation();
int dx = head.x - tail.x;
int dy = head.y - tail.y;
double angle = Math.atan2((double) dx, (double) dy);
angle = -angle*180/Math.PI+90;
if (angle < 0) angle += 360;
return angle;
}
public boolean insideRect(Point[] rect) {
return Geom.lineInsideRect(inPt.getLocation(), outPt.getLocation(), rect);
}
public String toString() {
return "(" + inPt + " to " + outPt + ")";
}
public static void main(String[] args) {
Edge e1, e2;
Link link = new Link();
e1 = new Edge(new NXPt(0, 4, link, 0), new NXPt(4, 4, link, 0), link, 0);
e2 = new Edge(new NXPt(1, 2, link, 0), new NXPt(1, 9, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e2 = new Edge(new NXPt(6, 0, link, 0), new NXPt(6, 3, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e2 = new Edge(new NXPt(6, 0, link, 0), new NXPt(1, 6, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e2 = new Edge(new NXPt(56, 0, link, 0), new NXPt(1, 6, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e1 = new Edge(new NXPt(0, 10, link, 0), new NXPt(15, 40, link, 0), link, 0);
e2 = new Edge(new NXPt(3, 25, link, 0), new NXPt(7, 15, link, 0), link, 0);
System.out.println(e1.intersect(e2));
}
}
Geom.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class Geom {
public static double angle(Point tail, Point head) {
// return "pseudo-angle" rather than true angle
// the value is
// |itan/(1+itan)| in the first quadrant
// |2-itan/(1+itan)| in the second quadrant
// |2+itan/(1+itan)| in the third quadrant
// |4-itan/(1+itan)| in the fourth quadrant
// remember that x increases to the right and y increases down
int tx = tail.x, ty = tail.y, hx = head.x, hy = head.y;
double dx = Math.abs(hx-tx);
double dy = Math.abs(hy-ty);
double res = dy/(dx+dy);
if (hx > tx) { // on RHS
if (hy > ty) res = 4.0 - res;
}
else { // on LHS
if (hy > ty) res = 2.0 + res;
else res = 2.0 - res;
}
return res;
}
public static boolean lineInsideRect(Point endpt1, Point endpt2, Point[] rect) {
// line is from endpt1 to endpt2
// rect[0] = (left, top), rect[1] = (right, bottom)
int left = rect[0].x, right = rect[1].x;
int top = rect[0].y, bottom = rect[1].y;
int x1 = endpt1.x, x2 = endpt2.x;
int y1 = endpt2.y, y2 = endpt2.y;
// if either endpt of line is inside the rect, part of line is inside
if (left < x1 && x1 < right && top < y1 && y1 < bottom) return true;
if (left < x2 && x2 < right && top < y2 && y2 < bottom) return true;
// now we know both endpts are outside
// part of line is inside iff the line intersects one of the edges
// get equation of line in the form f(x+y) = ax+by+c = 0
double a = 0, b = 0, c = 0;
a = y1 - y2;
b = x2 - x1;
c = -x2*y1 + x1*y2;
double left_top = a*left + b*top + c;
double right_top = a*right + b*bottom + c;
double left_bottom = a*left + b*bottom + c;
double right_bottom = a*right + b*bottom + c;
if ((x1 < left && left < x2) || (x2 < left && left < x1)) {
if (left_top*right_bottom < 0) return true;
}
if ((x1 < right && right < x2) || (x2 < right && right < x1)) {
if (right_top*right_bottom < 0) return true;
}
if ((y1 < top && top < y2) || (y2 < top && top < y1)) {
if (left_top*right_top < 0) return true;
}
if ((y1 < bottom && bottom < y2) || (y2 < bottom && bottom < y1)) {
if (left_bottom*right_bottom < 0) return true;
}
return false;
}
public static boolean nearerThan(Pt newPt, Point[] oldPoints, int nOldPoints,
int tolerance) {
int newX = newPt.x, newY = newPt.y;
int squaredTolerance = tolerance*tolerance;
for (int i = 0; i < nOldPoints; i++) {
int oldX = oldPoints[i].x,
oldY = oldPoints[i].y;
if ((newX-oldX)*(newX-oldX) + (newY-oldY)*(newY-oldY) < squaredTolerance)
return true;
}
return false;
}
public static void main(String[] args) throws Exception {
}
}
KntToJnk.java:
--------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class KntToJnk {
static int pageWidth = 340, pageHeight = 516;
static double scaleFactor = 0.55;
public static void convert(String kntName, String jnkName) {
BufferedReader br = null;
BufferedWriter bw = null, aw = null;
Link theLink = null;
try {
br = new BufferedReader(new FileReader(kntName));
LinkReader lr = new LinkReader(br);
int n = lr.getNLinks();
while (n-- > 0) {
theLink = lr.loadLink();
}
br.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
System.out.println("load aborted: " + kntName);
return;
}
try {
bw = new BufferedWriter(new FileWriter(jnkName));
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(theLink);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
System.out.println("save aborted: " + jnkName);
return;
}
}
public static void main(String[] args) {
// args: base int1 int2 e.g. h 3 7 to mean h3, h4, h5, h6, h7
if (args.length != 3 && args.length != 2) {
System.out.println("Usage: java kntToJnk base n1 [n2]");
System.exit(0);
}
int n1 = Integer.parseInt(args[1]);
int n2 = (args.length == 2) ? n1 : Integer.parseInt(args[2]);
for (int k = n1; k <= n2; k++)
convert(args[0] + ".knt", args[0] + ".jnk");
}
}
Link.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class Link {
public static int nextId = 0;
public static double HALF = 0.5;
public static double THIRD = 1.0/3.0;
public static int MAX_NKNOTS = 30;
public static int radius = 5;
public static final int NEITHER = 0;
public static final int OVER = 1;
public static final int UNDER = 2;
public static final int MIXED = 3;
public static final int OVER_IN = 0;
public static final int OVER_OUT = 1;
public static final int UNDER_IN = 2;
public static final int UNDER_OUT = 3;
public static final int CUT_DELTA = 5;
public static Color[] edgeColors = {
Color.black, Color.red, Color.green, Color.yellow, Color.cyan.darker().darker(),
};
public static String[] knotBWStrings = {
"2 setlinewidth 0.0 0.0 0.0 setrgbcolor",
"2 setlinewidth 0.3 0.3 0.3 setrgbcolor",
"2 setlinewidth 0.5 0.5 0.5 setrgbcolor",
"2 setlinewidth 0.7 0.7 0.7 setrgbcolor",
"2 setlinewidth 0.9 0.9 0.9 setrgbcolor",
};
public static String selectedEdgeBWString =
"2 setlinewidth 0.0 0.0 0.0 setrgbcolor";
static Color[] rgb = { Color.red, Color.green, Color.blue, };
int id;
int nKnots = 0, nOldKnots = 0;
int totalEdges = 0;
int nStrands = 0;
int[] tricoloring;
Edge[] firstEdge; // really entries into DLLs (knots)
int[] nKnotEdges;
XPt[] firstXPt;
boolean[] marked;
int[] nXPt;
int totalCrossings = 0;
XOPt r1iXOPt;
XOPt[] r2iXOPts;
XOPt[] macXOPts;
Edge firstSelectedEdge = null, lastSelectedEdge = null;
// edges selected for r1d/r1i/mac
public Link() {
id = ++nextId;
nKnots = 0;
firstEdge = new Edge[MAX_NKNOTS];
nKnotEdges = new int[MAX_NKNOTS];
firstXPt = new XPt[MAX_NKNOTS];
nXPt = new int[MAX_NKNOTS];
marked = new boolean[MAX_NKNOTS];
for (int i = 0; i < MAX_NKNOTS; i++) marked[i] = false;
}
public Link(Link orig) {
// construct a copy of orig
this();
System.out.println("in Link constructor with Link arg");
System.out.println("orig:");
orig.print();
System.out.println("end of orig");
nKnots = orig.nKnots;
totalCrossings = orig.totalCrossings;
totalEdges = orig.totalEdges;
for (int i = 0; i < nKnots; i++) {
nXPt[i] = orig.nXPt[i];
nKnotEdges[i] = orig.nKnotEdges[i];
}
Hashtable ht = new Hashtable();
for (int knotId = 0; knotId < nKnots; knotId++) {
System.out.print("knotId = " + knotId + " first edge = ");
XPt[] xPtArray = new XPt[nXPt[knotId]];
int xPtIndex = 0;
marked[knotId] = orig.marked[knotId];
Edge e1 = orig.firstEdge[knotId];
if (e1 == null) {
System.out.println("null");
firstEdge[knotId] = null;
continue;
}
System.out.println(e1.toString());
Pt startPt = e1.getInPt().makeCopy(ht, this);
Pt lastPt = e1.getOutPt().makeCopy(ht, this);
Edge startEdge = new Edge(startPt, lastPt, this, knotId);
if (e1 == orig.firstSelectedEdge) firstSelectedEdge = startEdge;
if (e1 == orig.lastSelectedEdge) lastSelectedEdge = startEdge;
Edge lastEdge = startEdge, currentEdge;
System.out.println("start pt = " + startPt.encoding() + " last pt = "
+ lastPt.encoding() + " start edge = " + startEdge.toString());
startPt.setOutEdge(startEdge);
lastPt.setInEdge(startEdge);
Edge ePrev = e1;
Edge e = e1.getNext();
System.out.println("before while loop nXPt[" + knotId + "] = " + nXPt[knotId]);
while (e.getNext() != e1) {
System.out.println("e = " + e.toString());
// if (e.getOutPt() instanceof XPt) nXPt[knotId]++;
if (ePrev.getOutPt() != e.getInPt())
lastPt = e.getInPt().makeCopy(ht, this);
Pt currentPt = e.getOutPt().makeCopy(ht, this);
if (currentPt instanceof XPt) xPtArray[xPtIndex++] = (XPt) currentPt;
currentEdge = new Edge(lastPt, currentPt, this, knotId);
System.out.println("current edge = " + currentEdge.toString());
if (e == orig.firstSelectedEdge) firstSelectedEdge = currentEdge;
if (e == orig.lastSelectedEdge) lastSelectedEdge = currentEdge;
lastEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
lastPt.setOutEdge(currentEdge);
currentPt.setInEdge(currentEdge);
lastEdge = currentEdge; lastPt = currentPt;
ePrev = e; e = e.getNext();
}
System.out.println("#XPts in knot#" + knotId + " = " + nXPt[knotId]);
// At this point, e is predecessor of e1
if (ePrev.getOutPt() != e1.getInPt())
lastPt = e.getInPt().makeCopy(ht, this);
if (e.getOutPt() != e1.getInPt())
startPt = e.getOutPt().makeCopy(ht, this);
currentEdge = new Edge(lastPt, startPt, this, knotId); // copy of e
if (e == orig.firstSelectedEdge) firstSelectedEdge = currentEdge;
if (e == orig.lastSelectedEdge) lastSelectedEdge = currentEdge;
if (lastSelectedEdge != null) {
lastSelectedEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
}
lastPt.setOutEdge(currentEdge);
startPt.setInEdge(currentEdge);
currentEdge.setNext(startEdge);
startEdge.setPrev(currentEdge);
firstEdge[knotId] = startEdge;
firstXPt[knotId] = (nXPt[knotId] == 0) ? null :
(XPt) orig.firstXPt[knotId].makeCopy(ht, this);
System.out.println("about to call copyLinkXPts");
copyLinkXPts(xPtArray);
System.out.println("back from copyLinkXPts");
}
}
public void markKnot(int knotId) {
marked[knotId] = !marked[knotId];
}
public Link makeSkeletonCopy() {
Link sk = new Link(this); // first make a duplicate
// now go through and delete all edges not incident on an XPt
sk.skeletonize();
return sk;
}
public void skeletonize() {
for (int i = 0; i < nKnots; i++)
skeletonize(i);
}
public void skeletonize(int i) {
if (nXPt[i] == 0) return;
XPt pFirst = firstXPt[i];
XPt p = pFirst;
do {
XPt pNext = p.getNext();
Edge e1 = p.getOutEdge();
Edge e2 = pNext.getInEdge();
if (e1 != e2 && e1.getNext() != e2) {
// make e1 connect to e2 directly, thereby
// removing intermediate edges
e1.setNext(e2); e2.setPrev(e1);
}
p = pNext;
} while (p != pFirst);
firstEdge[i] = pFirst.getOutEdge();
}
public int newKnot() {
firstEdge[nKnots] = null;
firstXPt[nKnots] = null;
nXPt[nKnots] = 0;
return nKnots++;
}
public int getNKnots() {
return nKnots;
}
public int getNStrands() {
return nStrands;
}
public int getNEdges(int knotId) {
Edge e = firstEdge[knotId];
if (e == null) return 0;
Edge e1 = e;
int ct = 0;
do {
ct++;
e = e.getNext();
} while (e != e1);
return ct;
}
public int getNXPt(int knotId) {
return nXPt[knotId];
}
public Edge getFirstEdge(int knotId) {
return firstEdge[knotId];
}
public void setFirstEdge(int knotId, Edge e) {
firstEdge[knotId] = e;
}
public XPt getFirstXPt(int knotId) {
return firstXPt[knotId];
}
public void setFirstXPt(int knotId, XPt xPt) {
firstXPt[knotId] = xPt;
}
public XUPt getFirstXUPt(int knotId) {
if (nXPt[knotId] == 0) return (XUPt) null;
XPt p = firstXPt[knotId];
XPt p1 = p;
do {
if (p instanceof XUPt) return (XUPt) p;
p = p.getNext();
} while (p != p1);
return (XUPt) null;
}
public void copyLinkXPts(XPt[] xPtArray) {
// create link list of XPt’s, after link is complete
System.out.println("in copyLinkXPts #XPts = " + xPtArray.length);
XPt firstXPt, lastXPt;
if (xPtArray.length == 0) return;
firstXPt = lastXPt = xPtArray[0];
for (int i = 1; i < xPtArray.length; i++) {
System.out.println("i = " + i);
XPt pp = xPtArray[i];
System.out.println("after assignment to pp");
lastXPt.setNext(pp);
System.out.println("after setNext");
pp.setPrev(lastXPt);
System.out.println("after setPrev");
lastXPt = pp;
System.out.println("at end of iteration for i = " + i);
}
// System.out.println("#XPts in knot#" + knotId + " = " + nXPt[knotId]);
System.out.println("after loop");
lastXPt.setNext(firstXPt);
firstXPt.setPrev(lastXPt);
System.out.println("returning from copyLinkXPts");
}
public void linkXPts(int knotId) {
// create link list of XPt’s, after link is complete
System.out.println("#edges in knot#" + knotId + " = " + nKnotEdges[knotId]);
XPt lastXPt;
Pt p;
Edge e = firstEdge[knotId];
Edge knotFirstEdge = e;
firstXPt[knotId] = null;
nXPt[knotId] = 0;
if (e == null) return;
p = null;
// for (int i = 0; i < nKnotEdges[knotId]; i++) {
do {
p = e.getOutPt();
if (p instanceof XPt) break;
e = e.getNext();
} while (e != knotFirstEdge);
System.out.println("after do-while loop");
if (p == null || !(p instanceof XPt)) return;
System.out.println("first XPt = " + p.encoding());
firstXPt[knotId] = lastXPt = (XPt) p;
nXPt[knotId]++;
e = e.getNext();
System.out.println("#edges in knot#" + knotId + " = " + nKnotEdges[knotId]);
// while (e != knotFirstEdge) {
for (int i = 0; i < nKnotEdges[knotId]-1; i++) {
p = e.getOutPt();
System.out.println("in loop i = " + i + " e = " + e.toString() + " p = "
+ p.encoding() + " knotFirstEdge = " +
knotFirstEdge.toString());
if (p instanceof XPt) {
XPt pp = (XPt) p;
lastXPt.setNext(pp);
pp.setPrev(lastXPt);
lastXPt = pp;
nXPt[knotId]++;
}
e = e.getNext();
System.out.println("new e = " + e.toString());
}
System.out.println("#XPts in knot#" + knotId + " = " + nXPt[knotId]);
lastXPt.setNext(firstXPt[knotId]);
firstXPt[knotId].setPrev(lastXPt);
}
public void linkXPts() {
for (int knotId = 0; knotId < nKnots; knotId++)
linkXPts(knotId);
}
public void clearSelectedEdges() {
firstSelectedEdge = lastSelectedEdge = null;
}
void absorbCollinear(int knotId) {
Edge e = getFirstEdge(knotId);
Pt p = null;
while (true) {
p = e.getInPt();
if ( !(p instanceof XPt) || !p.collinear() ) break;
e = e.getNext();
}
Pt q = e.getOutPt();
do {
if ( !(q instanceof XPt) || !q.collinear() )
e = e.getNext();
else e.absorbNext();
q = e.getOutPt();
} while (q != p);
setFirstEdge(knotId, e);
}
public void absorbCollinear() {
for (int knotId = 0; knotId < nKnots; knotId++)
absorbCollinear(knotId);
}
public void computeTotalCrossings() {
totalCrossings = 0;
for (int knotId = 0; knotId < nKnots; knotId++)
totalCrossings += nXPt[knotId];
totalCrossings /= 2;
}
public void wrapUp(boolean absorb) {
// if (absorb) absorbCollinear();
//System.out.println("after absorbCollinear");
linkXPts();
System.out.println("after linkXPts");
computeTotalCrossings();
System.out.println("after computeTotalCrossings");
totalEdges = 0;
for (int knotId = 0; knotId < nKnots; knotId++) {
nKnotEdges[knotId] = 0;
Edge e = firstEdge[knotId];
Edge e1 = e;
do {
totalEdges++; nKnotEdges[knotId]++;
e = e.getNext();
} while (e != e1);
}
}
public void wrapUp() {
wrapUp(true);
}
int nIntersect(Edge e, Edge startEdge, Edge endEdge,
Edge[][] crossingEdges, int oldNIntersect) {
while (true) {
double t = e.intersect(startEdge);
if (0 < t && t < 1) {
crossingEdges[oldNIntersect][0] = e;
crossingEdges[oldNIntersect][1] = startEdge;
oldNIntersect++;
}
if (startEdge == endEdge) break;
startEdge = startEdge.getNext();
}
return oldNIntersect;
}
Edge[][] exactResult(Edge[][] tempResult, int n) {
Edge[][] result = new Edge[n][2];
for (int i = 0; i < n; i++) {
result[i][0] = tempResult[i][0];
result[i][1] = tempResult[i][1];
}
return result;
}
Edge[][] newOldCrossings(Edge[] newChain, Edge e1, Edge e2,
int maxXPt) throws Exception {
// newChain to replace edges from e1 to e2
Edge[][] tempResult = new Edge[maxXPt][2];
int thisKnot = e1.getKnotId();
int nCrossings = 0;
try {
for (int knotId = 0; knotId < nKnots; knotId++) {
if (knotId != thisKnot) {
for (int i = 0; i < newChain.length; i++)
nCrossings = nIntersect(newChain[i], firstEdge[knotId],
firstEdge[knotId].getPrev(), tempResult,
nCrossings);
continue;
}
if (newChain.length == 1) {
Edge e = newChain[0];
if (e.getInPt() == e1.getInPt()) {
if (e.getOutPt() != e2.getOutPt()) { // exclude two edges
if (e2.getNext() != e1.getPrev() &&
e2.getNext() != e1.getPrev().getPrev())
nCrossings = nIntersect(e, e2.getNext().getNext(),
e1.getPrev().getPrev(), tempResult, nCrossings);
}
else { // exclude only e1’s predecessor
if (e2.getNext() != e1.getPrev())
nCrossings = nIntersect(e, e2.getNext(),
e1.getPrev().getPrev(), tempResult, nCrossings);
}
}
continue;
}
if (e2.getNext() != e1.getPrev()) {
if (newChain[0].getInPt() == e1.getInPt())
nCrossings = nIntersect(newChain[0], e2.getNext(),
e1.getPrev().getPrev(), tempResult, nCrossings);
nCrossings = nIntersect(newChain[newChain.length-1],
e2.getNext().getNext(), e1.getPrev().getPrev(),
tempResult, nCrossings);
}
for (int i = 1; i < newChain.length-1; i++)
nCrossings = nIntersect(newChain[i], e2.getNext(), e1.getPrev(),
tempResult, nCrossings);
}
}
catch (Exception anyExc) {
throw new Exception(); // subscript error in nIntersect
}
return exactResult(tempResult, nCrossings);
}
Edge[][] newOldCrossings(Edge newEdge, Edge e1, Edge e2,
int maxXPt) throws Exception {
Edge[] ea = new Edge[1];
ea[0] = newEdge;
return newOldCrossings(ea, e1, e2, maxXPt);
}
public void removeXPt(XPt x) {
int knotId = x.getKnotId();
nXPt[knotId]--;
if (nXPt[knotId] == 0) { // none remains
firstXPt[knotId] = null;
return;
}
XPt y = x.getPrev();
XPt z = x.getNext();
y.setNext(z); z.setPrev(y);
firstXPt[knotId] = y;
}
public void removeXPtPair(XPt x) {
// remove x and its mate
removeXPt(x);
removeXPt(x.getMate());
}
void linkIn(Edge eIn, Pt p, Edge eOut) {
eIn.setOutPt(p); eOut.setInPt(p);
eIn.setNext(eOut); eOut.setPrev(eIn);
p.setInEdge(eIn); p.setOutEdge(eOut);
}
public void r1d(Edge selectedEdge) throws Exception {
XPt xp1 = (XPt) selectedEdge.getInPt();
XPt xp2 = xp1.getMate();
if (xp1.getMate() != xp2) {
throw new Exception("r1d not applicable");
}
r1dSub(selectedEdge, xp1, xp2);
wrapUp();
}
public void r1dSub(Edge selectedEdge, XPt xp1, XPt xp2) throws Exception {
int knotId = xp1.getKnotId();
Edge e1 = selectedEdge.getPrev();
Edge e2 = xp2.getOutEdge();
e1.setNext(e2); e2.setPrev(e1);
Point p =xp1.getLocation();
Pt newCommonPt = new NXPt(p.x, p.y, this, knotId);
e1.setOutPt(newCommonPt);
e2.setInPt(newCommonPt);
newCommonPt.setInEdge(e1);
newCommonPt.setOutEdge(e2);
// update list of crossing points
setFirstEdge(knotId, e1);
}
boolean noXPtBtn(Edge e1, Edge e2) {
Edge e = e1;
while (e != e2) {
if (e.getOutPt() instanceof XPt) return false;
e = e.getNext();
}
return true;
}
Edge[] createNewArc(Pt entryPt, Pt[] interPts, int nInterPts,
Pt exitPt, int knotId) {
// create a sequence of edges using the points entryPt,
// the first nInterPts elements of interPts, and exitPt
Edge[] newEdges = new Edge[nInterPts+1];
if (nInterPts == 0) {
newEdges[0] = new Edge(entryPt, exitPt, this, knotId);
return newEdges;
}
newEdges[0] = new Edge(entryPt, interPts[0], this, knotId);
for (int i = 1; i < nInterPts; i++)
newEdges[i] = new Edge(interPts[i-1], interPts[i], this, knotId);
newEdges[nInterPts] = new Edge(interPts[nInterPts-1], exitPt,
this, knotId);
for (int i = 0; i < newEdges.length-1; i++)
linkIn(newEdges[i], interPts[i], newEdges[i+1]);
return newEdges;
}
Edge[][] selfCross(Edge startEdge, Edge endEdge, int maxXPt)
throws Exception {
// look for up to maxXPt among edges
// from startEdge to endEdge inclusive
if (startEdge == endEdge || startEdge.getNext() == endEdge)
return new Edge[0][2];
Edge[][] tempResult = new Edge[maxXPt][2];
Edge e = startEdge, e1 = e.getNext();
int nSelfCrossings = 0;
while (e1 != endEdge) {
e1 = e1.getNext(); // e1 two steps ahead of e
try {
nSelfCrossings = nIntersect(e, e1, endEdge, tempResult, nSelfCrossings);
}
catch (Exception anyExc) {
throw new Exception(); // subscript error
}
e = e.getNext();
}
return exactResult(tempResult, nSelfCrossings);
}
NXPt[] getPts(Point[] points, int nPoints) {
NXPt[] res = new NXPt[nPoints];
for (int i = 0; i < nPoints; i++)
res[i] = new NXPt(points[i].x, points[i].y, this, 0);
return res;
}
public void r1i(Edge e1, Edge e2, Point[] chosenPoints,
int nChosenPoints) throws Exception {
NXPt[] chosenPts = getPts(chosenPoints, nChosenPoints);
int knotId = e1.getKnotId();
if (!noXPtBtn(e1, e2)) throw new Exception("r1i across XPt's disallowed");
Pt e1InPt = e1.getInPt(), e2OutPt = e2.getOutPt();
Point e1Start = e1.getInPt().getLocation(),
e2End = e2.getOutPt().getLocation();
if (e1Start.equals(e2End)) throw new Exception("r1i edges form loop");
Edge e1Prev = e1.getPrev(), e2Next = e2.getNext();
for (int i = 0; i < nChosenPoints; i++)
chosenPts[i].setKnotId(knotId);
Edge[] newEdges = createNewArc(e1InPt, chosenPts, nChosenPoints, e2OutPt, knotId);
Edge[][] newCrossings = null;
try {
newCrossings = selfCross(newEdges[0], newEdges[nChosenPoints], 1);
}
catch (Exception anyExc) {
throw new Exception("multiple crossing points generated");
}
if (newCrossings.length == 0) {
throw new Exception("no crossing point");
}
linkIn(e1Prev, e1InPt, newEdges[0]);
linkIn(newEdges[newEdges.length-1], e2OutPt, e2Next);
Point temp;
int inx, iny, outx, outy;
temp = newCrossings[0][0].getInPt().getLocation();
inx = temp.x; iny = temp.y;
temp = newCrossings[0][0].getOutPt().getLocation();
outx = temp.x; outy = temp.y;
double t = newCrossings[0][0].intersect(newCrossings[0][1]);
int x = (int) Math.round((1-t)*inx + t*outx);
int y = (int) Math.round((1-t)*iny + t*outy);
XOPt thisMidPt = new XOPt(x, y, this, knotId, knotId);
r1iXOPt = thisMidPt;
newCrossings[0][0].splitEdge(thisMidPt);
newCrossings[0][1].splitEdge(thisMidPt.getMate());
firstEdge[knotId] = newEdges[0];
wrapUp();
}
public void r1iToggleCrossing() {
r1iXOPt.toggle();
linkXPts(r1iXOPt.getKnotId());
}
public Point getR1iXPtLoc() {
return r1iXOPt.getLocation();
}
int crossingType(Edge e1, Edge e2) {
Edge e = e1;
int result = NEITHER;
while (e != e2) {
Pt p = e.getOutPt();
if (p instanceof XPt) {
switch (result) {
case NEITHER:
if (p instanceof XUPt) result = UNDER;
else result = OVER;
break;
case OVER:
if (p instanceof XUPt) result = MIXED;
break;
case UNDER:
if (p instanceof XOPt) result = MIXED;
break;
}
}
e = e.getNext();
}
return result;
}
void switchMatesToNXPt(Edge e1, Edge e2) {
// go from edge e1 to e2, switching mates of all interior points
// that are XPt’s to NXPt’s
Edge ex = e1;
while (ex != e2) {
Pt p = ex.getOutPt();
if (p instanceof XPt) {
Point pLoc = p.getLocation();
Pt pMate = ((XPt) p).getMate();
Pt p1 = new NXPt(pLoc.x, pLoc.y, this, pMate.getKnotId());
Edge ePrev = pMate.getInEdge(), eNext = pMate.getOutEdge();
p1.setInEdge(ePrev); p1.setOutEdge(eNext);
ePrev.setOutPt(p1); eNext.setInPt(p1);
}
ex = ex.getNext();
}
}
public void mac(Edge e1, Edge e2, Point[] chosenPoints,
int nChosenPoints) throws Exception {
System.out.println("in Link.mac");
System.out.println("first edge = " + e1.toString() + " last edge = " +
e2.toString() + " #points = " + nChosenPoints);
NXPt[] chosenPts = getPts(chosenPoints, nChosenPoints);
int knotId = e1.getKnotId();
int interiorXPtsType = crossingType(e1, e2);
if (interiorXPtsType == MIXED)
throw new Exception("mac not applicable – mixed crossings");
Pt e1InPt = e1.getInPt(), e2OutPt = e2.getOutPt();
Point e1Start = e1InPt.getLocation(),
e2End = e2OutPt.getLocation();
System.out.println("e1Start = " + e1Start.x + "," + e1Start.y + " e2End = " +
e2End.x + "," + e2End.y);
if (e1Start.equals(e2End)) {
if (e1InPt == e2OutPt) {
throw new Exception("mac edges form loop");
} else { // must be a crossing point – mixed type 1 and type 2 move
System.out.println("mixed I & II move");
r1dSub(e1, (XPt) e1InPt, (XPt) e2OutPt);
switchMatesToNXPt(e1, e2);
wrapUp();
return;
}
}
Edge e1Prev = e1.getPrev(), e2Next = e2.getNext();
System.out.println("e1Prev = " + e1Prev.toString() + " e2Next = "
+ e2Next.toString());
for (int i = 0; i < nChosenPoints; i++)
chosenPts[i].setKnotId(knotId);
Edge[] newEdges = createNewArc(e1InPt, chosenPts, nChosenPoints, e2OutPt,
knotId);
System.out.println("#new edges = " + newEdges.length);
for (int i = 0; i < newEdges.length; i++)
System.out.println(newEdges[i].toString());
if (nChosenPoints > 0) {
try {
selfCross(newEdges[0], newEdges[nChosenPoints], 0);
} catch (Exception anyExc) {
throw new Exception("mac – self-crossings not allowed");
}
}
linkIn(e1Prev, e1InPt, newEdges[0]);
linkIn(newEdges[newEdges.length - 1], e2OutPt, e2Next);
System.out.println(e1Prev);
System.out.println(newEdges[0]);
System.out.println(newEdges[newEdges.length - 1]);
System.out.println(e2Next);
Edge[][] newCrossings = null;
try {
newCrossings = newOldCrossings(newEdges, e1, e2,
totalEdges * newEdges.length);
} catch (Exception anyExc) {
throw new Exception("mac – too many crossings: system error");
}
System.out.println("#crossings = " + newCrossings.length);
switchMatesToNXPt(e1, e2);
Point temp;
int inx, iny, outx, outy;
macXOPts = new XOPt[newCrossings.length];
int xOPtCt = 0;
for (int i = 0; i < newEdges.length; i++) {
Edge e = newEdges[i];
try {
newCrossings = newOldCrossings(e, e1, e2, totalEdges);
} catch (Exception anyExc) {
throw new Exception("mac – system error");
}
if (newCrossings.length == 0) continue;
double[] ta = new double[newCrossings.length];
for (int j = 0; j < ta.length; j++) {
ta[j] = e.intersect(newCrossings[j][1]);
}
for (int j = ta.length - 1; j > 0; j--)
for (int k = 0; k < j; k++)
if (ta[k] > ta[k + 1]) {
double tTemp = ta[k];
ta[k] = ta[k + 1];
ta[k + 1] = tTemp;
Edge eTemp = newCrossings[k][1];
newCrossings[k][1] = newCrossings[k + 1][1];
newCrossings[k + 1][1] = eTemp;
}
for (int j = ta.length - 1; j >= 0; j--) {
temp = e.getInPt().getLocation();
inx = temp.x;
iny = temp.y;
temp = e.getOutPt().getLocation();
outx = temp.x;
outy = temp.y;
double t = e.intersect(newCrossings[j][1]);
int x = (int) Math.round((1 - t) * inx + t * outx);
int y = (int) Math.round((1 - t) * iny + t * outy);
XOPt thisMidPt = new XOPt(x, y, this, knotId,
newCrossings[j][1].getKnotId());
macXOPts[xOPtCt++] = thisMidPt;
if (interiorXPtsType != UNDER) {
e.splitEdge(thisMidPt);
newCrossings[j][1].splitEdge(thisMidPt.getMate());
} else {
e.splitEdge(thisMidPt.getMate());
newCrossings[j][1].splitEdge(thisMidPt);
}
}
}
firstEdge[knotId] = newEdges[0];
wrapUp();
System.out.println("xOPtCt = " + xOPtCt);
if (xOPtCt == 0 || interiorXPtsType == NEITHER) macXOPts = null;
}
void setIsolated(int knotId) {
NXPt[] corners = new NXPt[4]; // nw – sw – se – ne
int x = knotId*(LinkCanvas.ISOLATED_DIST + LinkCanvas.ISOLATED_SIDE)
+ LinkCanvas.ISOLATED_DIST;
int y = LinkCanvas.ISOLATED_TOP_MARGIN;
corners[0] = new NXPt(x, y, this, knotId);
corners[1] = new NXPt(x, y+LinkCanvas.ISOLATED_SIDE, this, knotId);
corners[2] = new NXPt(x+LinkCanvas.ISOLATED_SIDE,
y+LinkCanvas.ISOLATED_SIDE, this, knotId);
corners[3] = new NXPt(x+LinkCanvas.ISOLATED_SIDE, y, this, knotId);
Edge[] edges = new Edge[4];
for (int i = 0; i < 4; i++)
edges[i] = new Edge(corners[i], corners[(i+1) % 4], this, knotId);
for (int i = 0; i < 4; i++) {
corners[i].setInEdge(edges[(i+3) % 4]);
corners[i].setOutEdge(edges[i]);
edges[i].setPrev(edges[(i+3) % 4]);
edges[i].setNext(edges[(i+1) % 4]);
}
firstEdge[knotId] = edges[0];
}
public void unlinkKnot(int knotId) {
for (int i = 0; i < nKnots; i++) {
if (i == knotId) continue;
XPt p = firstXPt[i];
if (p == null) continue;
XPt q = p;
do {
if (q.getMate().getKnotId() == knotId) {
Pt newPt = new NXPt(q);
Edge inEdge = newPt.getInEdge();
Edge outEdge = newPt.getOutEdge();
inEdge.setOutPt(newPt);
outEdge.setInPt(newPt);
newPt.setInEdge(inEdge);
newPt.setOutEdge(outEdge);
}
q = q.getNext();
} while (q != p);
}
deleteSplitUnknot(knotId);
wrapUp();
}
public void reverseKnot(int knotId) {
Edge start = getFirstEdge(knotId);
Edge end = start.getPrev();
Pt jct = start.getInPt();
Edge.reverseEdges(start, end);
jct.setInEdge(start);
jct.setOutEdge(end);
wrapUp();
}
public void makeReflection() {
XPt[] xPts = null;
for (int knotId = 0; knotId < nKnots; knotId++) {
if (nXPt[knotId] == 0) continue;
xPts = new XPt[nXPt[knotId]];
XPt p = firstXPt[knotId];
for (int i = 0; i < nXPt[knotId]; i++) {
xPts[i] = p;
p = p.getNext();
}
for (int i = 0; i < nXPt[knotId]; i++) {
p = xPts[i];
if (p instanceof XOPt) p.toggle();
}
}
wrapUp();
}
public void macToggleCrossings() {
for (int i = 0; i < macXOPts.length; i++)
macXOPts[i].toggle();
wrapUp();
}
Point[] getMacXPtLocArray() {
Point[] result = new Point[macXOPts.length];
for (int i = 0; i < macXOPts.length; i++)
result[i] = macXOPts[i].getLocation();
return result;
}
public boolean macCompleted() {
return macXOPts == null;
}
public void printXPts() {
for (int knotId = 0; knotId < nKnots; knotId++) {
System.out.print("knot #" + knotId + ": ");
if (nXPt[knotId] == 0) {
System.out.println("No crossing points");
continue;
}
XPt p = firstXPt[knotId];
System.out.println(nXPt[knotId] + " Crossing points ----");
do {
System.out.println(p + " " + p.getInEdge() + " " + p.getOutEdge());
p = p.getNext();
} while (p != firstXPt[knotId]);
}
System.out.println("--------------------");
}
public void appendEdge(int knotId, Edge e) {
if (firstEdge[knotId] == null) {
firstEdge[knotId] = e;
e.setPrev(e); e.setNext(e);
return;
}
Edge last = firstEdge[knotId].getPrev();
e.setPrev(last); e.setNext(firstEdge[knotId]);
last.setNext(e); firstEdge[knotId].setPrev(e);
}
public void detAlt(XPt p, boolean[] marked) {
XPt[] xa = new XPt[nKnots];
int xaCt = 0;
xa[xaCt++] = p;
marked[p.getKnotId()] = true;
while (xaCt > 0) {
XPt p1 = xa[--xaCt];
Pt p2 = p1;
boolean over = (p1 instanceof XOPt);
do {
if (p2 instanceof XPt) {
XPt p3 = (XPt) p2;
if (over != (p3 instanceof XOPt)) {
p3.toggle(); p2 = p3 = p3.getMate();
}
XPt mate = p3.getMate();
int mateKnotId = mate.getKnotId();
if (!marked[mateKnotId]) {
marked[mateKnotId] = true;
xa[xaCt++] = mate;
}
over = !over;
}
p2 = p2.getNextPt();
} while (p2 != p1);
}
}
boolean[] getMarked() {
boolean[] res = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) res[i] = false;
return res;
}
XPt findXPt(int knotId) {
Pt startPt = getFirstEdge(knotId).getInPt();
Pt p = startPt;
do {
if (p instanceof XPt) return (XPt) p;
p = p.getNextPt();
} while (p != startPt);
return (XPt) null;
}
public void setAlt() {
boolean[] marked = getMarked();
for (int i = 0; i < nKnots; i++) {
if (!marked[i]) detAlt(findXPt(i), marked);
}
}
public void setAlt(XPt p) {
boolean[] marked = getMarked();
detAlt(p, marked);
}
public int[] getMinMaxXY(int knotId) {
int minX, minY, maxX, maxY;
Edge e1 = getFirstEdge(knotId);
Point p = e1.getInPt().getLocation();
minX = maxX = p.x; minY = maxY = p.y;
Edge e = e1;
do {
p = e.getInPt().getLocation();
if (p.x < minX) minX = p.x;
else if (p.x > maxX) maxX = p.x;
if (p.y < minY) minY = p.y;
else if (p.y > maxY) maxY = p.y;
e = e.getNext();
} while (e != e1);
int[] res = new int[4];
res[0] = minX; res[1] = maxX; res[2] = minY; res[3] = maxY;
return res;
}
public int[] getMinMaxXY(boolean[] knotMask) {
// at least one entry in knotMask must be true
int[] res, res1;
int i = 0;
while (!knotMask[i]) i++;
res = getMinMaxXY(i);
while (++i < knotMask.length) {
if (!knotMask[i]) continue;
res1 = getMinMaxXY(i);
if (res1[0] > res[0]) res[0] = res1[0];
if (res1[1] > res[1]) res[1] = res1[1];
if (res1[2] > res[2]) res[2] = res1[2];
if (res1[3] > res[3]) res[3] = res1[3];
}
return res;
}
public int[] getMinMaxXY() {
boolean[] knotMask = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) knotMask[i] = true;
return getMinMaxXY(knotMask);
}
public boolean[] getKnotMask(int[] knotIds) {
boolean[] knotMask = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) knotMask[i] = false;
for (int i = 0; i < knotIds.length; i++) knotMask[knotIds[i]] = true;
return knotMask;
}
public void rotate(int[] knotIds, int degCcw) {
// rotate the knots indicated in the knotIds array, plus
// all knots that these cross directly or indirectly,
// through an angle of degCcw (degrees counterclockwise).
// The center of rotation is the centroid of the rectangle
// spanned by the rotated knots.
int[] minMaxXY = getMinMaxXY(getKnotMask(knotIds));
int midX = (int) Math.round((minMaxXY[0]+minMaxXY[1])/2.0);
int midY = (int) Math.round((minMaxXY[2]+minMaxXY[3])/2.0);
double radCcw = (degCcw * Math.PI) / 180.0;
double cos = Math.cos(radCcw);
double sin = Math.sin(radCcw);
for (int i = 0; i < knotIds.length; i++) {
Edge e1 = getFirstEdge(knotIds[i]);
Edge e = e1;
do {
Pt p = e.getInPt();
p.rotate(midX, midY, sin, cos);
e = e.getNext();
} while (e != e1);
}
}
public void rotate(int knotId, int degCcw) {
// rotate the knot with the specified knotId, plus
// all knots that it crosses directly or indirectly,
// through an angle of degCcw (degrees counterclockwise).
// The center of the rotation is the centroid of the rectangle
// spanned by the rotated knots.
int[] knotIds = { knotId };
rotate(knotIds, degCcw);
}
void dfs(int v, boolean[][] adj, boolean[] marked) {
// depth-first search: v represents a knot
marked[v] = true;
for (int i = 0; i < marked.length; i++)
if (adj[v][i] && !marked[i]) dfs(i, adj, marked);
}
public boolean isSplit() {
boolean[][] adj = new boolean[nKnots][nKnots];
for (int i = 0; i < nKnots; i++)
for (int j = 0; j < nKnots; j++)
adj[i][j] = false;
for (int i = 0; i < nKnots; i++) {
if (nXPt[i] == 0) return true;
XPt p = firstXPt[i];
boolean firstIsOver = (p instanceof XOPt);
boolean differ = false;
XPt p1 = p;
do {
int j = p.getMate().getKnotId();
if (i != j) {
System.out.println("adj: " + i + " " + j);
adj[i][j] =adj[j][i] = true;
}
p = p.getNext();
if (firstIsOver != (p instanceof XOPt)) differ = true;
} while (p != p1);
if (!differ) return true;
}
boolean[] marked = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) marked[i] = false;
dfs(0, adj, marked);
for (int i = 0; i < nKnots; i++)
if (!marked[i]) return true;
return false;
}
public void numberStrands() {
// only called if isSplit is true
nStrands = 0;
for (int i = 0; i < nKnots; i++) {
XPt p = firstXPt[i];
while (!(p instanceof XUPt)) p = p.getNext();
for (int j = 0; j < nXPt[i]; j++) {
p.getOutEdge().setStrandId(nStrands);
p = p.getNext();
p.getInEdge().setStrandId(nStrands);
if (p instanceof XUPt) nStrands++;
}
}
}
public void numberCrossings() {
int n = 0;
for (int i = 0; i < nKnots; i++) {
XPt p = firstXPt[i];
for (int j = 0; j < nXPt[i]; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
((XOPt) p).crossingId = n++;
}
}
}
public int[][] makeChecks() {
int[] nChecks = new int[nStrands];
for (int i = 0; i < nStrands; i++) nChecks[i] = 0;
for (int i = 0; i < nKnots; i++) {
if (nXPt[i] == 0) continue;
XPt p = firstXPt[i];
for (int j = 0; j < nXPt[i]; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
int maxStrand = p.getInEdge().getStrandId();
XPt pm = p.getMate(); // must be an XUPt
maxStrand = Math.max(maxStrand, pm.getInEdge().getStrandId());
maxStrand = Math.max(maxStrand, pm.getOutEdge().getStrandId());
}
}
int[][] checks = new int[nStrands][];
for (int i = 0; i < nStrands; i++) {
checks[i] = new int[2*nChecks[i]];
nChecks[i] = 0;
}
for (int i = 0; i < nKnots; i++) {
if (nXPt[i] == 0) continue;
XPt p = firstXPt[i];
for (int j = 0; j < nXPt[i]; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
int[] strands = new int[3];
strands[0] = p.getInEdge().getStrandId();
XPt pm = p.getMate();
strands[1] = pm.getInEdge().getStrandId();
strands[2] = pm.getOutEdge().getStrandId();
// sort the strands, just enough to have max last
// that is, only one pass of bubblesort is done
for (int k = 0; k < 2; k++)
if (strands[k] > strands[k+1]) {
int temp = strands[k];
strands[k] = strands[k+1];
strands[k+1] = temp;
}
int maxStrand = strands[2];
int jj = 2*nChecks[maxStrand]++;
checks[maxStrand][jj+1] = strands[i];
}
}
for (int i = 0; i < checks.length; i++) {
System.out.print("strand " + i + ":");
for (int j = 0; j < checks.length; j++)
System.out.print(" " + checks[i][j]);
System.out.println();
}
return checks;
}
boolean colorOk(int[] colors, int s, int c, int[][] checks) {
// assign color c to strand s
int i = 0;
colors[s] = c;
while (i < checks.length) {
int other0 = colors[checks[s][i]];
int other1 = colors[checks[s][i+1]];
if (other0 == other1 && c != other0) return false;
if (other0 != other1 && (c == other0 || c == other1)) return false;
i += 2;
}
if (s == nStrands-1) { // color assignment complete
// look for 2 different colors
for (int j = 1; j < colors.length; j++)
if (colors[j] != colors[0]) return true;
return false;
}
for (int j = 0; j < 3; j++)
if (colorOk(colors, j+1, s, checks)) return true;
return false;
}
public boolean tricolorable() {
numberStrands();
int[][] checks = makeChecks();
tricoloring = new int[nStrands];
tricoloring[0] = 0;
return colorOk(tricoloring, 1, 0, checks)
|| colorOk(tricoloring, 1, 1, checks);
}
void setFourEdges(XPt p, int[] edgeKind, double[] edgeAngle) {
// p must be an XOPt
XPt pm = p.getMate();
edgeKind[0] = OVER_IN;
edgeAngle[0] = p.getInEdge().getReverseAngle();
edgeKind[1] = OVER_OUT;
edgeAngle[1] = p.getOutEdge().getAngle();
edgeKind[2] = UNDER_IN;
edgeAngle[2] = pm.getInEdge().getReverseAngle();
edgeKind[3] = UNDER_OUT;
edgeAngle[3] = pm.getInEdge().getAngle();
}
void sortFourEdges(int[] edgeKind, double[] edgeAngle) {
for (int ii = 3; ii > 0; ii--)
for (int jj = 0; jj < ii; jj++)
if (edgeAngle[jj] > edgeAngle[jj+1]) {
double tempAngle = edgeAngle[jj];
edgeAngle[jj] = edgeAngle[jj+1];
edgeAngle[jj+1] = tempAngle;
int tempKind = edgeKind[jj];
edgeKind[jj] = edgeKind[jj+1];
edgeKind[jj+1] = tempKind;
}
}
int[][] getCodedMatx() throws Exception {
if (isSplit()) throw new Exception("splittable – Alex poly is zero");
numberStrands();
if (nStrands != totalCrossings)
throw new Exception("#strands = " + nStrands + " #crossings = " +
totalCrossings);
int[][] codedMatx = new int[totalCrossings][3];
// for each i, codedMatx[i][0] = col. index of 1-t entry
// codedMatx[i][1] = col. index of -1 entry
// codedMatx[i][2] = col. index of t entry
int crossingId = 0;
int[] edgeKind = new int[5];
double[] edgeAngle = new double[4];
for (int j = 0; j < nKnots; j++) {
XPt p = firstXPt[j];
for (int k = 0; k < nXPt[j]; k++, p = p.getNext()) {
if (p instanceof XUPt) continue;
XPt pm = p.getMate();
setFourEdges(p, edgeKind, edgeAngle);
sortFourEdges(edgeKind, edgeAngle);
edgeKind[4] = edgeKind[0]; // to handle circularity
int overOut = 0;
while (edgeKind[overOut] != OVER_OUT) overOut++;
codedMatx[crossingId][0] = p.getOutEdge().getStrandId();
int underInIndex = 1;
if (edgeKind[overOut+1] != UNDER_OUT) underInIndex = 2;
codedMatx[crossingId][underInIndex] = pm.getInEdge().getStrandId();
codedMatx[crossingId][3-underInIndex] = pm.getOutEdge().getStrandId();
crossingId++;
}
}
return codedMatx;
}
public int[] alex() throws Exception {
int[][] codedMatx = getCodedMatx();
double[] polyDouble = NumAnal.newtonInterp(codedMatx);
int[] polyInt = new int[nStrands];
for (int j = 0; j < nStrands; j++)
polyInt[j] = (int) Math.round(polyDouble[j]);
return polyInt;
}
public void writeLine(BufferedWriter bw, String s) {
try {
bw.write(s, 0, s.length());
bw.newLine();
}
catch (Exception anyExc) {
}
}
public void saveAlex(BufferedWriter bw) throws Exception {
int[][] codedMatx = getCodedMatx();
int n = codedMatx.length;
writeLine(bw, "> with linalg,det;");
writeLine(bw, "> A=array([seq(0,ii=1.." + (n-1)
+ ")],jj=1.." + (n-1) + ")]);" );
for (int j = 0; j < n-1; j++) {
if (codedMatx[j][0] < n-1)
writeLine(bw, "> A[" + (j+1) + "," +
(codedMatx[j][0]+1) + "]:=1-t;" );
if (codedMatx[j][1] < n-1)
writeLine(bw, "> A[" + (j+1) + "," +
(codedMatx[j][1]+1) + "]:=-1" );
if (codedMatx[j][2] < n-1)
writeLine(bw, "> A[" + (j+1) + "," +
(codedMatx[j][2]+1) + "]:=t" );
}
writeLine(bw, "> det(A);");
}
public XOPt findXOPt(Point p) {
int squaredRadius = radius*radius;
for (int j = 0; j < nKnots; j++) {
if (nXPt[j] == 0) continue;
XPt xp = firstXPt[j];
for (int k = 0; k < nXPt[j]; k++, xp = xp.getNext()) {
if (xp instanceof XUPt) continue;
Point xpLoc = xp.getLocation();
if ((xpLoc.x - p.x)*(xpLoc.x - p.x) + (xpLoc.y - p.y)*(xpLoc.y - p.y)
>= squaredRadius) continue;
return (XOPt) xp;
}
}
return (XOPt) null;
}
XOPt findFirstXOPt() {
for (int j = 0; j < nKnots; j++) {
if (nXPt[j] == 0) continue;
XPt xp = firstXPt[j];
for (int k = 0; k < nXPt[j]; k++, xp = xp.getNext()) {
if (xp instanceof XUPt) continue;
return (XOPt) xp;
}
}
return (XOPt) null;
}
void standardizeEdges(int[] edgeKind, double[] edgeAngle) {
// sort and rotate the arrays so that in counterclockwise
// order, we have out0, out1, in0, in1 as follows
// out1 - -ïƒ out0
// \ /
// \ /
// \/
// /\
// / \
// / \
// in0 >------- \ ----ïƒ in1
sortFourEdges(edgeKind, edgeAngle);
while (! (edgeKind[0] == OVER_OUT && edgeKind[1] == UNDER_OUT
|| edgeKind[0] == UNDER_OUT && edgeKind[1] == OVER_OUT ) ) {
Util.leftRotate1(edgeKind, 4); // 4 is size, not amount of rotation
Util.leftRotate1(edgeAngle, 4);
}
}
boolean isRightHanded(XOPt p) {
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
return (edgeKind[0] == OVER_OUT);
}
void setKnotId(Edge e, int knotId) {
Edge e1 = e;
do {
e.setKnotId(knotId);
e.getInPt().setKnotId(knotId);
e.getOutPt().setKnotId(knotId);
e = e.getNext();
} while (e != e1);
}
void setParentLink(Edge e, Link link) {
Edge e1 = e;
do {
e.setParentLink(link);
e.getInPt().setParentLink(link);
e.getOutPt().setParentLink(link);
e = e.getNext();
} while (e != e1);
}
public void joinVertical(XOPt p) {
if (!isRightHanded(p)) {
p.toggle();
wrapUp();
joinHorizontal(p);
}
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge(); out1 = pm.getOutEdge();
in0 = p.getInEdge(); in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
joinEdges(in0, out1);
joinEdges(in1, out0);
if (overKnotId == underKnotId) { // a knot splits into two
int newKnotId = nKnots++;
firstEdge[overKnotId] = out1;
firstEdge[newKnotId] = out0;
setKnotId(in1, newKnotId);
}
else { // two knots become one
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp();
}
public void joinHorizontal(XOPt p) {
if (!isRightHanded(p)) {
p.toggle();
wrapUp();
joinVertical(p);
return;
}
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge();
out1 = pm.getOutEdge();
in0 = p.getInEdge();
in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
NXPt elbow0 = new NXPt(p);
NXPt elbow1 = new NXPt(p);
out0.setInPt(elbow0); out1.setInPt(elbow0);
in0.setOutPt(elbow1); in1.setOutPt(elbow1);
in0.setNext(in1); in1.setNext(in0);
out0.setPrev(out1); out1.setPrev(out0);
elbow0.setInEdge(out1); elbow0.setOutEdge(out0);
elbow1.setInEdge(in1); elbow1.setOutEdge(in0);
if (overKnotId == underKnotId) { // a knot stays one knot
elbow1.setInEdge(in1); elbow1.setOutEdge(in0);
Edge.reverseEdges(out1, in0);
joinEdges(out1, out0);
joinEdges(in1, in0);
}
else { // two knots become one
elbow1.setInEdge(in0); elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
joinEdges(out1, out0);
joinEdges(in0, in1);
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp();
}
public void bktJoinVertical(XOPt p) {
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge(); out1 = pm.getOutEdge();
in0 = p.getInEdge(); in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
NXPt elbow0 = new NXPt(p);
NXPt elbow1 = new NXPt(p);
in0.setOutPt(elbow0); out1.setInPt(elbow0);
in1.setOutPt(elbow1); out0.setInPt(elbow1);
in0.setNext(in1); in1.setNext(in0);
out0.setPrev(out1); out1.setPrev(out0);
elbow0.setInEdge(out1); elbow0.setOutEdge(out0);
elbow1.setInEdge(in1); elbow1.setOutEdge(in0);
if (overKnotId == underKnotId) { // a knot stays one knot
elbow1.setInEdge(in0); elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
}
else { // two knots become one
elbow1.setInEdge(in0); elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp();
}
public void bktJoinHorizontal(XOPt p) {
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge(); out1 = pm.getOutEdge();
in0 = p.getInEdge(); in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
NXPt elbow0 = new NXPt(p);
NXPt elbow1 = new NXPt(p);
out0.setInPt(elbow0); out1.setInPt(elbow0);
in0.setOutPt(elbow1); in1.setOutPt(elbow1);
in0.setNext(in1); in1.setNext(in0);
out0.setPrev(out1); out1.setPrev(out0);
if (overKnotId == underKnotId) { // a knot stays one knot
elbow1.setInEdge(in1);
elbow1.setOutEdge(in0);
Edge.reverseEdges(out1, in0);
}
else { // two knots become one
elbow1.setInEdge(in0);
elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId == nKnots - 1) {
firstEdge[freedKnotId] = firstEdge[nKnots - 1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp(false);
}
NXPt cutPoint(Pt a, Pt b) {
// a point between a and b, backed up a distance of
// CUT_DELTA from b. If this is too large, use midpt of
// a and b instead.
Point ap = a.getLocation();
Point bp = b.getLocation();
int dx = b.x - a.x;
int dy = b.y - a.y;
double length = Math.sqrt((double) (dx*dx + dy*dy));
if (length < 2*CUT_DELTA)
return new NXPt((a.x+b.x)/2, (a.y+b.y)/2, this, 0);
int x = (int) (bp.x - dx*CUT_DELTA/length);
int y = (int) (bp.y - dy*CUT_DELTA/length);
return new NXPt(x, y, this, 0);
}
void joinEdges(Edge in, Edge out) {
NXPt interm1 = cutPoint(in.getInPt(), in.getOutPt());
NXPt interm2 = cutPoint(out.getOutPt(), out.getInPt());
Edge bridge = new Edge(interm1, interm2, this, 0);
in.setOutPt(interm1);
out.setInPt(interm2);
interm1.setInEdge(in); interm1.setOutEdge(bridge);
interm2.setInEdge(bridge); interm2.setOutEdge(out);
in.setNext(bridge); bridge.setNext(out);
out.setPrev(bridge); bridge.setPrev(in);
}
public void nullify(XOPt pOver) {
XUPt pUnder = (XUPt) pOver.getMate();
int overKnotId = pOver.getKnotId();
int underKnotId = pUnder.getKnotId();
Edge overIn = pOver.getInEdge();
Edge underIn = pUnder.getInEdge();
Edge overOut = pOver.getOutEdge();
Edge underOut = pUnder.getOutEdge();
joinEdges(underIn, overOut);
joinEdges(overIn, underOut);
if (underKnotId == overKnotId) { // a knot splits into two
int newKnotId = nKnots++;
firstEdge[overKnotId] = overOut;
firstEdge[underKnotId] = underOut;
setKnotId(overOut, newKnotId);
setKnotId(underOut, newKnotId);
}
else { // two knots become one
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(underIn, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp(false);
}
int findSplitUnknot() {
for (int ii = 0; ii < nKnots; ii++)
if (nXPt[ii] == 0) return ii;
return -1;
}
void deleteSplitUnknot(int knotId) {
int oldLast = --nKnots;
if (knotId == oldLast) return;
if (firstEdge[oldLast] == null) {
firstEdge[knotId] = null;
nXPt[knotId] = 0;
firstXPt[knotId] = null;
return;
}
firstEdge[knotId] = firstEdge[oldLast];
nXPt[knotId] = nXPt[oldLast];
firstXPt[knotId] = firstXPt[oldLast];
setKnotId(firstEdge[oldLast], knotId);
}
void deleteConsecXPts(XPt p, XPt q) {
// link must be skeletonized.
// p must be predecessor of q in list of XPts for the knot
// p and q must form a Type I or Type II configuration
// this function only deletes p and q, not their mates
// in case of a Type II configuration
int knotId = p.getKnotId();
if (nXPt[knotId] == 2) {
// no more XPts left in knot
nXPt[knotId] = 0;
firstEdge[knotId] = null;
firstXPt[knotId] = null;
return;
}
NXPt pNew = new NXPt(p), qNew = new NXPt(q);
p.getInEdge().setOutPt(pNew); p.getOutEdge().setInPt(pNew);
q.getInEdge().setOutPt(qNew); q.getOutEdge().setInPt(qNew);
XPt pPrev = p.getPrev();
XPt qNext = q.getNext();
pPrev.setNext(qNext); qNext.setPrev(pPrev);
Edge e1 = pPrev.getOutEdge();
Edge e2 = qNext.getInEdge();
e1.setNext(e2); e2.setPrev(e1);
nXPt[knotId] -= 2;
firstEdge[knotId] = e2;
firstXPt[knotId] = qNext;
}
public void simplifyIAndII() {
// link must be skeletonized
// look for and remove all Types I and II configurations
// note that removing such configurations might lead to more
// such configurations to be removed (the more the better)
int n = nKnots;
// n is decremented each time we go through a knot with no change
// when a knot is changed, n is reset to nKnots
// outer loop stops only when n is 0, i.e. we hav gone
// thru all the knots with no change in any
int knotId = 0;
for ( ; n > 0; knotId = (knotId+1) % nKnots) {
boolean knotChanged = false;
int m = nXPt[knotId];
// m controls the inner loop in a manner similar to
// how n controls the outer loop
if (m == 0) {
n--; continue;
}
XPt p = firstXPt[knotId];
while (m > 0) {
XPt pm = p.getMate();
XPt q = p.getNext(), qm = q.getMate();
if (q == pm) { // Type I
deleteConsecXPts(p, q);
m = nXPt[knotId]; // hav to go through all remaining XPts
p = firstXPt[knotId];
knotChanged = true;
continue;
}
if ( (p instanceof XOPt) == (q instanceof XOPt) &&
(pm.getNext() == qm || pm.getPrev() == qm) ) { // Type II
deleteConsecXPts(p, q);
if (pm.getNext() == qm) deleteConsecXPts(pm, qm);
else deleteConsecXPts(qm, pm);
m = nXPt[knotId];
knotChanged = true;
continue;
}
m--; p = q;
}
if (knotChanged) n = nKnots;
else n--;
}
}
public static LPoly bktPoly(Link x) {
int splitUnknot = x.findSplitUnknot();
if (splitUnknot >= 0) {
if (x.nKnots == 1) return LPoly.ONE;
else {
x.deleteSplitUnknot(splitUnknot);
return LPoly.NEG_A2A_2.mul(bktPoly(x));
}
}
Link x1 = new Link(x);
XOPt xp = x1.findFirstXOPt();
boolean rightHanded = x1.isRightHanded(xp);
x1.bktJoinVertical(xp);
Link x2 = new Link(x);
x2.bktJoinVertical(xp);
LPoly p1 = bktPoly(x1);
LPoly p2 = bktPoly(x2);
if (rightHanded) return
LPoly.A.mul(p1).add(LPoly.A_1.mul(p2));
else return
LPoly.A.mul(p2).add(LPoly.A_1.mul(p1));
}
public int writhe() {
int res = 0;
for (int ii = 0; ii < nKnots; ii++) {
if (nXPt[ii] == 0) continue;
XPt p = firstXPt[ii];
int n = nXPt[ii];
for (int j = 0; j < n; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
if (isRightHanded( (XOPt) p ) ) res++;
else res--;
}
}
return res;
}
public int selfWrithe() {
int res = 0;
for (int ii = 0; ii < nKnots; ii++) {
if (nXPt[ii] == 0) continue;
XPt p = firstXPt[ii];
int n = nXPt[ii];
for (int j = 0; j < n; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
if (p.getKnotId() != p.getMate().getKnotId()) continue;
if (isRightHanded( (XOPt) p ) ) res++;
else res--;
}
}
return res;
}
public int linkingNumber() {
int res = 0;
for (int ii = 0; ii < nKnots; ii++) {
if (nXPt[ii] == 0) continue;
XPt p = firstXPt[ii];
int n = nXPt[ii];
for (int j = 0; j < n; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
if (p.getKnotId() == p.getMate().getKnotId()) continue;
if (isRightHanded( (XOPt) p ) ) res++;
else res--;
}
}
return res/2;
}
public static LPoly fBktPoly(Link x) {
// hopefully a faster version
Link simplifiedCopy = new Link(x);
simplifiedCopy.simplifyIAndII();
x.computeTotalCrossings();
simplifiedCopy.computeTotalCrossings();
if (simplifiedCopy.totalCrossings < x.totalCrossings) {
int w0 = x.writhe();
int w1 = simplifiedCopy.writhe();
LPoly factor = new LPoly( new Term (
( (w0-w1)%2 == 0) ? 1 : -1, 3*(w0-w1) ) );
return factor.mul(fBktPoly(simplifiedCopy));
}
int splitUnknot = x.findSplitUnknot();
if (splitUnknot >= 0) {
if (x.nKnots == 1) return LPoly.ONE;
else {
x.deleteSplitUnknot(splitUnknot);
return LPoly.NEG_A2A_2.mul(bktPoly(x));
}
}
Link x1 = new Link(x);
XOPt xp = x1.findFirstXOPt();
boolean rightHanded = x1.isRightHanded(xp);
x1.bktJoinVertical(xp);
Link x2 = new Link(x);
xp = x2.findFirstXOPt();
x2.bktJoinHorizontal(xp);
LPoly p1 = bktPoly(x1);
LPoly p2 = bktPoly(x2);
if (rightHanded) return
LPoly.A.mul(p1).add(LPoly.A_1.mul(p2));
else return
LPoly.A.mul(p2).add(LPoly.A_1.mul(p1));
}
public void print() {
for (int knotId = 0; knotId < nKnots; knotId++) {
System.out.println("knot #" + knotId + ":");
if (firstEdge[knotId] == null) {
System.out.println("empty knot");
continue;
}
Edge e = firstEdge[knotId];
do {
e.print();
e = e.getNext();
} while (e != firstEdge[knotId]);
}
}
public void draw(Graphics g, int nKnotsToDraw, boolean ignoreCrossing) {
// System.out.println("in Link.draw link to draw:");
// print();
// System.out.println("end of link to draw");
for (int knotId = 0; knotId < nKnotsToDraw; knotId++) {
// System.out.println("knot#" + knotId + ":");
Edge knotFirstEdge = firstEdge[knotId];
if (knotFirstEdge == null) continue;
Edge e = knotFirstEdge;
Color edgeColor = edgeColors[knotId % edgeColors.length];
for (int i = 0; i < nKnotEdges[knotId]; i++) {
// System.out.println(e.toString());
e.draw(g, edgeColor, ignoreCrossing, marked[knotId]);
e = e.getNext();
}
firstEdge[knotId].drawArrow(g, edgeColor, ignoreCrossing, false);
}
}
public void draw(Graphics g, boolean ignoreCrossing) {
draw(g, nKnots, ignoreCrossing);
}
public void xorDraw(Graphics g, int startKnotId, boolean ignoreCrossing) {
Color edgeColor = Color.green;
for (int knotId = startKnotId; knotId < nKnots; knotId++) {
Edge knotFirstEdge = firstEdge[knotId];
if (knotFirstEdge == null) continue;
Edge e = knotFirstEdge;
do {
e.xorDraw(g, edgeColor, ignoreCrossing);
e = e.getNext();
} while (e != knotFirstEdge);
}
}
public void erase(Graphics g, Color c, boolean ignoreCrossing) {
for (int knotId = 0; knotId < nKnots; knotId--) {
Edge knotFirstEdge = firstEdge[knotId];
if (knotFirstEdge == null) continue;
Edge e = knotFirstEdge;
do {
e.draw(g, c, ignoreCrossing, !marked[knotId]);
e = e.getNext();
} while (e != knotFirstEdge);
}
}
public void tricolorDraw(Graphics g) {
for (int knotId = 0; knotId < nKnots; knotId++) {
if (nXPt[knotId] == 0) continue;
XPt p = firstXPt[knotId];
XPt pu = null;
for (int j = 0; j < nXPt[knotId]; j++) {
if (p instanceof XUPt) {
pu = p; break;
}
p = p.getNext();
}
if (pu == null) continue;
Edge knotFirstEdge = firstEdge[knotId];
Edge e = knotFirstEdge;
int colorIndex = 0;
do {
if (e.getInPt() instanceof XUPt)
colorIndex = tricoloring[e.getStrandId()];
e.draw(g, rgb[colorIndex], false, !marked[knotId]);
e = e.getNext();
} while (e != knotFirstEdge);
}
}
public int dupChosenKnot(Edge e) {
// duplicate knot containing edge e, returns old #knots
Link dupLink = new Link(this);
int dupKnotId = e.getKnotId();
XPt p = dupLink.firstXPt[dupKnotId];
int n = dupLink.nXPt[dupKnotId];
for (int j = 0; j < n; j++, p = p.getNext()) {
// get rid of crossings with other knots
if (p.getMate().getKnotId() == dupKnotId) continue;
NXPt p1 = new NXPt(p);
Edge e1 = p1.getInEdge();
Edge e2 = p1.getOutEdge();
p1.setInEdge(e1); p1.setOutEdge(e2);
e1.setOutPt(p1); e2.setInPt(p1);
}
int newKnotId = nKnots++;
firstEdge[newKnotId] = dupLink.firstEdge[dupKnotId];
setKnotId(firstEdge[newKnotId], newKnotId);
setParentLink(firstEdge[newKnotId], this);
absorbCollinear(newKnotId);
linkXPts(newKnotId);
return newKnotId;
}
public int addLink(Link linkToAdd) {
// add link, return old #knots
Link dupLink = new Link(linkToAdd);
int n = nKnots;
int n1 = dupLink.nKnots;
for (int j = 0; j < n1; j++) {
firstEdge[n+j] = dupLink.firstEdge[j];
setKnotId(firstEdge[n+j], n+j);
setParentLink(firstEdge[n+j], this);
linkXPts(n+j);
}
nKnots += n1;
return n;
}
public int dupLink() {
return addLink(this);
}
public void moveKnot(int knotId, int dx, int dy) {
Edge e = firstEdge[knotId];
Edge e1 = e;
do {
Pt p = e.getInPt();
Point pLoc = p.getLocation();
p.setX(pLoc.x + dx);
p.setY(pLoc.y + dy);
e = e.getNext();
} while (e != e1);
}
public void moveKnots(int startKnotId, int dx, int dy) {
for (int j = startKnotId; j < nKnots; j++)
moveKnot(j, dx, dy);
}
public void doubleY() {
for (int j = 0; j < nKnots; j++) {
Edge e = firstEdge[j];
if (e == null) continue;
Edge e1 = e;
do {
Pt p = e.getInPt();
Point pLoc = p.getLocation();
p.setY(2*pLoc.y);
e = e.getNext();
} while (e != e1);
}
}
public void hiliteCrossings(Graphics g, int radius) {
Color oldColor = g.getColor();
g.setColor(Color.blue);
for (int j = 0; j < nKnots; j++) {
if (nXPt[j] == 0) continue;
XPt p = firstXPt[j];
XPt pFirst = p;
do {
if (p instanceof XOPt) {
Point pLoc = p.getLocation();
g.drawOval(pLoc.x - radius, pLoc.y - radius, 2 * radius, 2 * radius);
}
p = p.getNext();
} while (p != pFirst);
}
g.setColor(oldColor);
}
public static String[] getKnotColorStrings() {
String[] res = new String[edgeColors.length];
for (int j = 0; j < edgeColors.length; j++) {
Color c = edgeColors[j];
res[j] = "2 setlinewidth " + c.getRed() + " "
+ c.getGreen() + " " + c.getBlue()
+ " setrgbcolor";
}
return res;
}
public static String getSelectedEdgeColorString() {
return "1 setlinewidth 0 0 1 setrgbcolor";
}
public static String[] getKnotBWStrings() {
return knotBWStrings;
}
public static String getSelectedEdgeBWString() {
return "1 setlinewidth 0 0 0 setrgbcolor";
}
public Boolean knotOutsideClipRect(int knotId, Point[] clipRect) {
// clipRect[0] = (left, top); clipRect[1] = (right, bottom)
Edge start = firstEdge[knotId];
Edge e = start;
do {
if (e.insideRect(clipRect)) return false;
e = e.getNext();
} while (e != start);
return true;
}
public Vector getUnfitPts(int leftX, int rightX, int tolerance) {
// return a Vector of all the Pt’s in the link whose
// x-distance from either leftX or rightX is less than
// tolerance
Vector res = new Vector();
for (int j = 0; j < nKnots; j++) {
Edge e = firstEdge[j];
Edge e1 = e;
do {
if (e.unfitForIterate(leftX, rightX, tolerance))
res.addElement(e.inPt);
e = e.getNext();
} while (e != e1);
}
return res;
}
public Vector getCrossedEdge(int leftX, int rightX) {
// return a Vector all Edges in the link that are
// crossed by the vertical lines x = leftX and x = rightX
Vector res = new Vector();
int left = 0, right = 0;
for (int j = 0; j < nKnots; j++) {
Edge e = firstEdge[j];
Edge e1= e;
do {
int x1 = e.inPt.x;
int x2 = e.outPt.x;
if ((x1 < leftX) == (leftX < x2) ||
(x1 < rightX) == (rightX < x2)) {
res.addElement(e);
if ((x1 < leftX) == (leftX < x2)) left++;
if ((x1 < rightX) == (rightX < x2)) right++;
}
e = e.getNext();
} while (e != e1);
}
res.addElement(new Integer(left));
res.addElement(new Integer(right));
return res;
}
}
LinkCanvas.java:
----------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkCanvas extends Canvas
implements MouseListener, MouseMotionListener,
ActionListener {
static final int BETWEEN_KNOTS = 1;
static final int VERTEX = 2;
static final int CROSSING = 3;
static final int COMPLETE = 4;
static final int STRAIGHTEN = 5;
static final int R1I = 6;
static final int R1I_CROSSING = 7;
static final int R2I = 8;
static final int R2I_CROSSING = 9;
static final int R3 = 10;
static final int MAC = 10;
static final int MAC_CROSSING = 11;
static final int UNLINK_KNOT = 12;
static final int UNLINK_CONFIRM = 13;
static final int RECT_UNKNOT = 14;
static final int ROTATE = 15;
static final int ROTATE_CONFIRM = 16;
static final int TRICOLOR = 17;
static final int SKELETON = 18;
static final int JOIN_VERTICAL = 19;
static final int JOIN_HORIZONTAL = 20;
static final int BKT_POLY = 21;
static final int SIMPLIFY = 22;
static final int DUP_KNOT_CHOOSE = 23;
static final int DUP_KNOT_MOVE = 24;
static final int REVERSE_KNOT = 25;
static final int REVERSE_CONFIRM = 26;
static final int NULLIFY = 27;
static final int EXPAND = 28;
static final int EXPAND_CROSSING = 29; // choosing a crossing for expand
static final int CLIP_RECT = 30;
static final int FIRST_EDGE = 31;
static final int MARK_KNOT = 32;
static final int MULTI_KNT = 33;
static final int MULTI_KNT_UNLINK = 34;
static final int MULTI_KNT_CONFIRM = 35;
static final int ZIGZAG = 36;
static final int ITERATE = 37;
static final int REFLECT_CONFIRM = 38;
static final int HOMFLY = 1;
static final int BRACKET = 2;
static final String[] modeNames =
{ "", "BETWEEN_KNOTS", "VERTEX", "CROSSING", "COMPLETE", "STRAIGHTEN",
"R1I", "R1I_CROSSING", "R2I", "R2I_CROSSING", "R3", "MAC",
"MAC_CROSSING", "UNLINK_KNOT", "UNLINK_CONFIRM", "RECT",
"TRICOLOR", "SKELETON", "JOIN_VERTICAL", "JOIN_HORIZONTAL",
"BKT_POLY", "SIMPLIFY", "DUP_KNOT_CHOOSE", "DUP_KNOT_MOVE",
"REVERSE_KNOT", "REVERSE_CONFIRM", "NULLIFY", "EXPAND",
"EXPAND_CROSSING",
"CLIP_RECT", "FIRST_EDGE", "MARK_KNOT", "MULTI_KNT",
"MULTI_KNT_UNLINK", "MULTI_KNT_CONFIRM", "ZIGZAG", "ITERATE",
"REFLECT_CONFIRM",
};
static final int EDGES_MODE = 1;
static final int POINTS_MODE = 2;
static final int RADIUS = 5;
static final int MIN_LENGTH = 15;
static final int INIT_LINK_EDGEMAX = 16;
static final int INIT_HISTORYMAX = 1000;
static final int MAX_CHOSEN_PTS = 100;
static final int tolerance = 5;
static final int RECT_TOLERANCE = 8;
static final double ONE_THIRD = 1.0/3.0;
static final double TWO_THIRDS = 2.0/3.0;
static final int NODES_BAR_X = 10;
static final int NODES_BAR_Y = 30;
static final int ITERATE_DX = 20;
static final int ITERATE_GAP = 20;
static final int ITERATE_HOWMANY = 20;
static final int NONE = 0, PRESENT = 1;
int arcRadius = 5;
int radius = 5;
// knots that are unlinked are retained in the link so that
// the remaining knots can retain their knot id’s and colors.
// These unlinked knots are displayed as square unknots in
// a reserved area at the top of the canvas. The constants
// below define the size, location and separation for these
// square unknots. Note that the location of each unlinked
// unknot is determined by its knot id. The other knots in
// link are not allowed to occupy the area with y <
// FORBIDDEN_Y.
public static final int ISOLATED_SIDE = 10;
public static final int ISOLATED_TOP_MARGIN = 3;
public static final int ISOLATED_BOTTOM_MARGIN = 3;
static final int FORBIDDEN_Y = ISOLATED_TOP_MARGIN +
ISOLATED_SIDE + ISOLATED_BOTTOM_MARGIN;
public static final int ISOLATED_DIST = 5;
public static final int GRID_DELTA = 10;
Frame frame;
int state = BETWEEN_KNOTS, pickMode, oldState;
boolean gridOn = true;
Link link, oldLink = null, reverseOrig;
// UnitLink iterLink = null;
int knotId;
NXPt startPt;
NXPt newPt;
NXPt lastPt;
Edge lastEdge, newEdge;
int intersectCt = 0;
double[] ta;
Edge[] ea;
XOPt[] xoa;
int[] xptx, xpty;
int knotEdgeCt = 0, linkEdgeCt = 0;
int inx, iny, outx, outy;
int linkEdgeMax = INIT_LINK_EDGEMAX;
int historyMax = INIT_HISTORYMAX;
int seriesMax = INIT_HISTORYMAX;
int nChosenEdges = 0, nChosenPoints = 0;
Edge chosenEdge1, chosenEdge2, lastClickedEdge, lastChosenEdge;
Point[] chosenPoints;
Point[] pa1 = new Point[1], pa2 = new Point[2];
Point lastPtLoc = new Point(200, 200);
boolean altFlag, reviewMode = false;
Link skeletonCopy;
Link clipboard = null;
// TreeNode root, currentNode;
double scaleFactor = 0.45;
int expandType = 0;
String currKntName = null, lastKntName = null;
String lastLoadName = null;
Image background = null;
Edge selectEdge;
Point lastClickedPoint = null, lastDupPoint = null;
Image offscreen;
int nOldKnots = 0;
Vector pts = null, edges = null;
Link[] history;
int[] seriesStart;
String[] seriesName;
int nLinks, nSeries, currentLink, currentSeries;
int rectLeft, rectTop, rectWidth, rectHeight;
int rectStage;
int clipCt, drawClipCt = 0;
Rectangle[] updateClipRegions = null;
int pageWidth = 600, pageHeight = 750;
Dialog headingDialog, scaleFactorDialog, pageSizeDialog;
TextField headingTF, scaleFactorTF, pageSizeTF;
String multiKntFilename;
int underlinePos = 0;
int degCcw = 0; // number of degrees to rotate, counterclockwise
static int boxWd = 270, boxHt = 220;
String[] translations = {
"30 540 translate", "310 540 translate",
"310 300 translate", "30 300 translate",
"30 60 translate", "310 60 translate",
};
String[] initPopupCmds = {
"draw",
// "draw w/ bg",
"load",
// "tangle", "pretzel", "braid", "torus",
// "(load tree", "homfly tree", "bracket tree", ")",
};
String[] betweenKnotsPopupCmds = {
"complete", "paste", "add load", "dup knot", "dup link", "print",
};
String[] vertexPopupCmds = {
"undo", "close |", "close _", "close", "cancel knot", // "zigzag",
"print",
};
String[] confirmPopupCmds = {
"confirm", "alternate",
};
String[] altPopupCmds = {
"confirm", "alternate",
};
String[] nonaltPopupCmds = {
"confirm", "non-alternate",
};
String[] completePopupCmds = {
"r1d", "r1i", "mac",
"(new", "draw",
// "draw w/ bg",
"load",
// "tangle", "pretzel", "braid", "torus",
")",
// "remove bg",
"(save", "save link", "save series", "save Jenkins",
"save knt", "save multi knt",
"save PS", "save PS BW", "save all Jenkins",
// "save Alex",
")",
"init", "load",
"copy", "add",
"(manipulate", "reflect",
// "flip horizontal", "flip vertical",
"unlink knot", "reverse knot", "double Y",
"toggle mark", ")",
"(rotate", "90 ccw", "180 ccw", "270 ccw", ")", "review",
"(test",
// "alex", "wirtinger",
"tricolor",
// "bkt poly", // "fbkt poly",
// "homfly", "homfly-new",
// "KL-compare",
// "Kauffman-L-new",
// "Kauffman-unoriented",
// "Kauffman-F",
// "Kauffman-F-G",
// "simplify", "skeleton", "nullify", "||", "=",
")", "grid toggle",
"first edge",
// "(tree expand", "homfly", "bracket", ")",
// "(load tree", "homfly tree", "bracket tree", ")",
"exit",
};
String[] expandPopupCmds = {
"r1d", "r1i", "mac",
// "expand", "cut",
// "up", "down", "sibling", "next",
// "(navigate", "forward", "backward", "first", "last", ")",
// "heading", "save tree", "save tree PS",
// "scale", "page size", "irst page", "toggle mark", "report", "quit",
};
String[] donePopupCmds = {
"done",
};
String[] cancelPopupCmds = {
"cancel",
};
String[] confirmCancelPopupCmds = {
"confirm", "cancel",
};
String[] pickPopupCmds = {
// "clip",
"points", "undo", "edges", "complete", "complete |",
"complete –", "cancel",
};
String[] reviewPopupCmds = {
"copy", "resume", "copy/resume",
"(save", "save knt",
"save PS", "save PS BW",
"save Jenkins", "save all Jenkins",
// "save Alex",
")",
"prev series", "next series", "first series", "last series",
};
String[] multiKntPopupCmds = {
"continue", "done multi",
};
// String[] iteratePopupCmds = {
// "make knots", "make matrix",
// "cancel",
// };
PopupMenu initPopupMenu, betweenKnotsPopupMenu, vertexPopupMenu,
confirmPopupMenu, quitPopupMenu, completeKnotPopupMenu,
completePopupMenu, pickPopupMenu, reviewPopupMenu,
altPopupMenu, nonaltPopupMenu, cancelPopupMenu,
confirmCancelPopupMenu, expandPopupMenu, donePopupMenu,
multiKntPopupMenu, iteratePopupMenu;
PopupMenu currentPopupMenu = null, oldPopupMenu = null;
Dimension preferredSize;
Label infoLabel, statusLabel;
boolean initializing = true;
LinkCanvas(Frame f, Dimension prefSize, Label infoLabel, Label statusLabel) {
// LPoly2.init();
frame = f;
preferredSize = prefSize;
this.infoLabel = infoLabel;
this.statusLabel = statusLabel;
setBackground(Color.white);
addMouseListener(this);
addMouseMotionListener(this);
chosenPoints = new Point[MAX_CHOSEN_PTS];
initPopupMenu = MakePopupMenu.make(initPopupCmds, this);
betweenKnotsPopupMenu = MakePopupMenu.make(betweenKnotsPopupCmds, this);
vertexPopupMenu = MakePopupMenu.make(vertexPopupCmds, this);
confirmPopupMenu = MakePopupMenu.make(confirmPopupCmds, this);
altPopupMenu = MakePopupMenu.make(altPopupCmds, this);
nonaltPopupMenu = MakePopupMenu.make(nonaltPopupCmds, this);
completePopupMenu = MakePopupMenu.make(completePopupCmds, this);
pickPopupMenu = MakePopupMenu.make(pickPopupCmds, this);
reviewPopupMenu = MakePopupMenu.make(reviewPopupCmds, this);
confirmCancelPopupMenu = MakePopupMenu.make(confirmCancelPopupCmds, this);
cancelPopupMenu = MakePopupMenu.make(cancelPopupCmds, this);
confirmPopupMenu = MakePopupMenu.make(confirmPopupCmds, this);
expandPopupMenu = MakePopupMenu.make(expandPopupCmds, this);
donePopupMenu = MakePopupMenu.make(donePopupCmds, this);
multiKntPopupMenu = MakePopupMenu.make(multiKntPopupCmds, this);
// iteratePopupMenu = MakePopupMenu.make(iteratePopupCmds, this);
completeKnotPopupMenu = completePopupMenu;
history= new Link[historyMax];
seriesStart = new int[seriesMax];
seriesName = new String[seriesMax];
createArrays();
nLinks = 0;
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
setPopupMenu(initPopupMenu);
// makeOffscreen();
// updateDiagram();
// initPopupMenu.show(this, 200, 200);
}
public void setArcRadius(int r) {
arcRadius = r;
}
public void showInitPopupMedu() {
initPopupMenu.show(this, 200, 200);
}
void setPopupMenu(PopupMenu pm) {
if (pm == null) {
System.out.println("setPopupMenu: null pm state = " + state);
return;
}
if (currentPopupMenu == pm) return;
if (currentPopupMenu != pm) remove(currentPopupMenu);
add(currentPopupMenu = pm);
}
protected void processMouseEvent(MouseEvent e) {
if (e.isPopupTrigger() && currentPopupMenu != null)
currentPopupMenu.show(e.getComponent(), e.getX(), e.getY());
super.processMouseEvent( e );
}
void review() {
setPopupMenu(reviewPopupMenu);
statusLabel.setText("Review");
currentLink = nLinks-1;
currentSeries = nSeries-1;
}
void resume() {
setPopupMenu(completePopupMenu);
statusLabel.setText("Link complete");
link = history[nLinks-1];
currentSeries = nSeries - 1;
currentLink = nLinks - 1;
reviewMode = false;
updateInfoAndDiagram();
}
void copyResume() {
addSeries();
addHistory(new Link(history[currentLink]));
history[nLinks-1].clearSelectedEdges();
resume();
}
void copy() {
clipboard = new Link(link);
}
void paste(Link pastedLink) {
makeOffscreen();
lastDupPoint = null;
nOldKnots = link.addLink(pastedLink);
Graphics g = offscreen.getGraphics();
link.xorDraw(g, nOldKnots, true);
state = DUP_KNOT_MOVE;
updateInfoAndDiagram();
statusLabel.setText("drag to move added link");
}
void paste() {
if (clipboard == null) {
statusLabel.setText("no link in clipboard");
return;
}
paste(clipboard);
}
void prevLink() {
if (currentLink == 0) return;
link = history[--currentLink];
if (currentSeries > 0 && currentLink < seriesStart[currentSeries])
currentSeries--;
updateInfoAndDiagram();
}
void nextLink() {
if (currentLink >= nLinks-1) return;
link = history[++currentLink];
if (currentSeries < nSeries-1 &&
currentLink == seriesStart[currentSeries+1])
currentSeries++;
updateInfoAndDiagram();
}
void firstLink() {
currentLink = 0;
currentSeries = 0;
link = history[currentLink];
updateInfoAndDiagram();
}
void lastLink() {
currentLink = nLinks-1;
currentSeries = nSeries-1;
link = history[currentLink];
updateInfoAndDiagram();
}
void prevSeries() {
if (currentSeries == 0) return;
currentLink = seriesStart[--currentSeries];
link = history[currentLink];
updateInfoAndDiagram();
}
void nextSeries() {
if (currentSeries >= nSeries-1) return;
currentLink = seriesStart[++currentSeries];
link = history[currentLink];
updateInfoAndDiagram();
}
void firstSeries() {
firstLink();
}
void lastSeries() {
currentSeries = nSeries-1;
currentLink = seriesStart[currentSeries];
link = history[currentLink];
updateInfoAndDiagram();
}
public void actionPerformed(ActionEvent e) {
System.out.println("in actionPerformed");
if (e.getSource() instanceof TextField) {
TextField tf = (TextField) e.getSource();
String s = tf.getText();
if (tf == headingTF) {
// currentNode.setHeading(s);
headingDialog.dispose();
return;
}
else if (tf == scaleFactorTF) {
scaleFactor = Double.valueOf(s).doubleValue();
scaleFactorDialog.dispose();
return;
}
else if (tf == pageSizeTF) {
int blankPos = s.indexOf(" ");
if (blankPos < 0) return;
int w = Integer.parseInt(s.substring(0, blankPos));
int h = Integer.parseInt(s.substring(blankPos+1));
pageWidth = w; pageHeight = h;
pageSizeDialog.dispose();
return;
}
}
String cmd = e.getActionCommand();
System.out.println("cmd = " + cmd);
if (cmd.equals("exit")) exitPressed();
else if (cmd.equals("complete")) completePressed();
else if (cmd.equals("complete |")) completeVert();
else if (cmd.equals("complete _")) completeHoriz();
else if (cmd.equals("cancel")) cancelPressed();
else if (cmd.equals("cancel knot")) cancelKnot();
else if (cmd.equals("cancel rect")) cancelKnot();
else if (cmd.equals("confirm")) confirmPressed();
else if (cmd.equals("alternate")) alternate();
else if (cmd.equals("non-alternate")) nonAlternate();
else if (cmd.equals("reflect")) reflect();
// else if (cmd.equals("flip vertical")) flipVertical();
// else if (cmd.equals("flip horizontal")) flipHorizontal();
else if (cmd.equals("unlink knot")) unlinkKnot();
else if (cmd.equals("reverse knot")) reverseKnot();
else if (cmd.equals("print")) printLink();
else if (cmd.equals("close")) closeKnot();
else if (cmd.equals("close |")) closeVert();
else if (cmd.equals("close _")) closeHoriz();
else if (cmd.equals("edges")) edges();
else if (cmd.equals("points")) points();
else if (cmd.equals("undo")) undo();
// else if (cmd.equals("zigzag")) zigzag();
// else if (cmd.equals("flip")) flip();
else if (cmd.equals("r1d")) r1d();
else if (cmd.equals("r1i")) r1i();
else if (cmd.equals("mac")) mac();
else if (cmd.equals("draw")) init();
// else if (cmd.equals("draw w/ bg")) init_bg();
// else if (cmd.equals("remove bg")) remove_bg();
else if (cmd.equals("load")) load();
// else if (cmd.equals("tangle")) tangle("tangle");
// else if (cmd.equals("pretzel")) tangle("pretzel");
// else if (cmd.equals("braid")) tangle("braid");
// else if (cmd.equals("torus")) tangle("torus");
else if (cmd.equals("save link")) saveLink();
else if (cmd.equals("save series")) saveSeries();
else if (cmd.equals("save multi knt")) saveMultiKnt();
// else if (cmd.equals("continue")) continueMultiKnt();
else if (cmd.equals("done multi")) doneMultiKnt();
else if (cmd.equals("save PS")) savePS(false); // arg is bwFlag
else if (cmd.equals("save PS BW")) savePS(true);
else if (cmd.equals("save Jenkins")) saveJenkins();
else if (cmd.equals("save all Jenkins")) saveAllJenkins();
// else if (cmd.equals("save Alex")) saveAlex();
else if (cmd.equals("add")) addInit();
else if (cmd.equals("dup knot")) dupKnot();
else if (cmd.equals("dup link")) dupLink();
else if (cmd.equals("double Y")) doubleY();
else if (cmd.equals("90 ccw")) rotate(90);
else if (cmd.equals("180 ccw")) rotate(180);
else if (cmd.equals("270 ccw")) rotate(270);
else if (cmd.equals("review")) review();
else if (cmd.equals("tricolor")) tricolor();
// else if (cmd.equals("skeleton")) skeleton();
// else if (cmd.equals("simplify")) simplify();
// else if (cmd.equals("bkt poly")) bktPoly();
// else if (cmd.equals("fbkt poly")) fBktPoly();
// else if (cmd.equals("homfly")) homfly();
// else if (cmd.equals("KL-compare")) KL_compare();
// else if (cmd.equals("Kauffman L")) KL();
// else if (cmd.equals("Kauffman unoriented")) Kauffman_unoriented();
// else if (cmd.equals("||")) setState(JOIN_VERTICAL, cancelPopupMenu);
// else if (cmd.equals("=")) setState(JOIN_HORIZONTAL, cancelPopupMenu);
// else if (cmd.equals("nullify")) setState(NULLIFY, cancelPopupMenu);
// else if (cmd.equals("alex")) alex();
// else if (cmd.equals("wirtinger")) wirtinger();
else if (cmd.equals("grid toggle")) toggleGrid();
else if (cmd.equals("copy")) copy();
else if (cmd.equals("paste")) paste();
else if (cmd.equals("add load")) addLoadLink();
else if (cmd.equals("resume")) resume();
else if (cmd.equals("copy/resume")) copyResume();
else if (cmd.equals("prev link")) prevLink();
else if (cmd.equals("next link")) nextLink();
else if (cmd.equals("first link")) firstLink();
else if (cmd.equals("last link")) lastLink();
else if (cmd.equals("prev series")) prevSeries();
else if (cmd.equals("next series")) nextSeries();
else if (cmd.equals("first series")) firstSeries();
else if (cmd.equals("last series")) lastSeries();
// else if (cmd.equals("homfly")) startExpand(HOMFLY);
// else if (cmd.equals("bracket")) startExpand(BRACKET);
// else if (cmd.equals("homfly tree")) loadTree(HOMFLY);
// else if (cmd.equals("bracket tree")) loadTree(BRACKET);
// else if (cmd.equals("expand")) expand();
// else if (cmd.equals("quit")) quitExpand();
// else if (cmd.equals("forward")) forward();
// else if (cmd.equals("backward")) backward();
// else if (cmd.equals("first")) firstInTreeNode();
// else if (cmd.equals("last")) lastInTreeNode();
// else if (cmd.equals("save tree")) saveTree();
// else if (cmd.equals("save tree PS")) saveTreePS();
// else if (cmd.equals("load tree")) loadTree();
// else if (cmd.equals("heading")) getHeading();
// else if (cmd.equals("scale")) getScaleFactor();
else if (cmd.equals("first edge")) firstEdge();
else if (cmd.equals("toggle mark")) markKnot();
else if (cmd.equals("done")) doneSelected();
// else if (cmd.equals("report")) collectTerms();
// else if (cmd.equals("cut")) cut();
// else if (cmd.equals("page size")) getPageSize();
}
void unlinkKnot() {
if (link.getNKnots() < 2) {
statusLabel.setText("only 1 unknot – can’t unlink");
return;
}
reverseOrig = new Link(link);
pushState(UNLINK_KNOT, cancelPopupMenu);
statusLabel.setText("click knot to unlink");
}
void reverseKnot() {
reverseOrig = new Link(link);
if (link.getNKnots() < 2) {
Link orig = new Link(link);
addSeries();
addHistory(orig, link);
link.reverseKnot(0);
pushState(REVERSE_CONFIRM, confirmCancelPopupMenu);
statusLabel.setText("confirm or cancel");
return;
}
pushState(REVERSE_KNOT, confirmCancelPopupMenu);
statusLabel.setText("click knots to reverse");
}
void reflect() {
reverseOrig = new Link(link);
link.makeReflection();
pushState(REFLECT_CONFIRM, confirmCancelPopupMenu);
statusLabel.setText("confirm or cancel");
updateDiagram();
}
/*
void flipHorizontal() {
addHistory(link.makeHorizontalFlip());
link = history[nLinks-1];
currKntName = null;
report(currKntName);
updateDiagram();
}
void flipVertical() {
addHistory(link.makeVerticalFlip());
link = history[nLinks-1];
currKntName = null;
report(currKntName);
updateDiagram();
}
*/
void rotate(int degCcw) {
if (link.getNKnots() == 1) {
Link orig = new Link(link);
try {
link.rotate(0, degCcw);
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
return;
}
tentativeAddHistory(orig, ROTATE_CONFIRM);
return;
}
this.degCcw = degCcw;
pushState(ROTATE, cancelPopupMenu);
statusLabel.setText("click knot to rotate");
}
void doubleY() {
Link orig = new Link(link);
link.doubleY();
updateDiagram();
}
void printLink() {
link.print();
}
void createArrays() {
Edge[] oldea = ea;
double[] oldta = ta;
int[] oldxptx = xptx, oldxpty = xpty;
XOPt[] oldxoa = xoa;
ea = new Edge[linkEdgeMax];
ta = new double[linkEdgeMax];
xptx = new int[linkEdgeMax];
xpty = new int[linkEdgeMax];
xoa = new XOPt[linkEdgeMax];
for (int ii = 0; ii < intersectCt; ii++) {
ea[ii] = oldea[ii]; ta[ii] = oldta[ii];
xptx[ii] = oldxptx[ii]; xpty[ii] = oldxpty[ii];
xoa[ii] = oldxoa[ii];
}
}
void addSeries() {
if (nSeries == seriesMax) {
seriesMax *= 2;
int[] temp = new int[seriesMax];
for (int ii = 0; ii < seriesStart.length; ii++)
temp[ii] = seriesStart[ii];
seriesStart = temp;
String[] stringTemp = new String[seriesMax];
for (int i = 0; i < seriesStart.length; i++)
stringTemp[i] = seriesName[i];
seriesName = stringTemp;
}
seriesStart[nSeries++] = nLinks;
currentSeries = nSeries - 1;
}
void addHistory(Link link) {
if (nLinks == historyMax) {
historyMax *= 2;
Link[] temp = new Link[historyMax];
for (int ii = 0; ii < history.length; ii++)
temp[ii] = history[ii];
history = temp;
}
history[nLinks++] = link;
currentLink = nLinks - 1;
currKntName = null;
}
void addHistory(Link orig, Link newLink) {
// if (root != null) { // in tree expansion mode
// currentNode.addHistory(orig, newLink);
// return;
// }
history[nLinks-1] = orig;
addHistory(newLink);
}
void initState() {
link = new Link();
addSeries();
addHistory(link);
linkEdgeCt = 0;
intersectCt = 0;
pts = new Vector();
edges = new Vector();
completeKnot();
setPopupMenu(completeKnotPopupMenu);
statusLabel.setText("between knots");
}
public void init() {
currKntName = null;
initState();
updateInfoAndDiagram();
}
/*
void loadBackground() {
LoadFileDialog lfd = new LoadFileDialog(frame);
try {
BufferedReader br = lfd.getLoadFile("Load Background", "*.gif");
String backgroundName = lfd.getLoadFileName();
background = getToolkit().getImage(backgroundName);
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(background, 0);
tracker.waitForID(0);
}
catch (Exception anyExc) {
statusLabel.setText("load background aborted");
return;
}
}
public void init_bg() {
loadBackground();
init();
}
public void remove_bg() {
background = null;
updateDiagram();
}
*/
void addInit() {
link = new Link(link);
addSeries();
addHistory(link);
if (linkEdgeMax < 2*link.totalCrossings) {
linkEdgeMax = 2*link.totalCrossings;
createArrays();
}
linkEdgeCt = link.totalEdges;
intersectCt = 0;
link.nOldKnots = link.getNKnots();
for (int i = 0; i < link.getNKnots(); i++) {
XPt p = link.getFirstXPt(i);
if (p == null) continue;
XPt p1 = p;
do {
if (p instanceof XOPt) {
Point loc = p.getLocation();
xptx[intersectCt] = loc.x;
xpty[intersectCt] = loc.y;
intersectCt++;
}
p = p.getNext();
} while (p != p1);
}
completeKnot();
setPopupMenu(betweenKnotsPopupMenu);
statusLabel.setText("between knots");
}
void makeOffscreen() {
MediaTracker tracker = new MediaTracker(this);
int curWidth = preferredSize.width,
curHeight = preferredSize.height;
offscreen = createImage(curWidth, curHeight);
tracker.addImage(offscreen, 0);
try { tracker.waitForID(0); }
catch (InterruptedException anyExc) { }
Graphics og = offscreen.getGraphics();
paint(og);
}
void dupKnot() {
setPopupMenu(cancelPopupMenu);
makeOffscreen();
if (link.getNKnots() == 1) {
lastDupPoint = null;
nOldKnots = link.dupChosenKnot(link.getFirstEdge(0));
state = DUP_KNOT_MOVE;
Graphics g = offscreen.getGraphics();
link.xorDraw(g, nOldKnots, true);
updateInfoAndDiagram();
statusLabel.setText("drag to move new copy");
return;
}
state = DUP_KNOT_CHOOSE;
statusLabel.setText("click knot to duplicate");
}
void dupLink() {
setPopupMenu(cancelPopupMenu);
makeOffscreen();
lastDupPoint = null;
nOldKnots = link.dupLink();
state = DUP_KNOT_MOVE;
Graphics g = offscreen.getGraphics();
link.xorDraw(g, nOldKnots, true);
updateInfoAndDiagram();
statusLabel.setText("drag to move new copy");
return;
}
void report(String seriesName) {
infoLabel.setText("#" + currentSeries + ":" + (currentLink - seriesStart[currentSeries])
+ " " + seriesName + ": " + "#comps = "
+ link.getNKnots() + " #crossings = " + link.totalCrossings
+ " writhe = " + link.writhe()
+ " self-writhe = " + link.selfWrithe()
+ " linking number = " + link.linkingNumber()
);
}
void loadFromFile(BufferedReader br) throws Exception {
LinkReader lr = new LinkReader(br);
int nLinks = lr.getNLinks();
System.out.println("#links in file = " + nLinks);
if (nLinks <= 0) return;
addSeries();
for (int i = 0; i < nLinks; i++) {
link = lr.loadLink();
// System.out.println("i = " + i + " #knots = " + link.nKnots);
// System.out.println("loaded link is:");
// link.print();
// System.out.println("end of link");
addHistory(link);
}
System.out.println("finished loading from file lastLoadName = " + lastLoadName);
currKntName = lastLoadName;
if (currKntName.toUpperCase().endsWith(".KNT"))
currKntName = currKntName.substring(0, currKntName.length()-4);
if (currKntName.toUpperCase().endsWith("-SER"))
currKntName = currKntName.substring(0, currKntName.length()-4);
// System.out.println("currentSeries = " + currentSeries);
seriesName[currentSeries] = currKntName;
try { br.close(); } catch (Exception anyExc) { }
state = COMPLETE;
setPopupMenu(completePopupMenu);
System.out.println("about to call report");
report(currKntName);
updateDiagram();
System.out.println("at end of loadFromFile state = " + state);
}
void loadFromFileName(String name) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(name));
lastLoadName = Util.getLastComponent(name);
loadFromFile(br);
}
void load() {
LoadFileDialog lfd = new LoadFileDialog(frame);
BufferedReader br;
try {
br = lfd.getLoadFile("Load Links", "*.knt");
lastLoadName = Util.getLastComponent(lfd.getLoadFileName());
System.out.println("loading from: " + lastLoadName);
loadFromFile(br);
System.out.println("returned from loadFromFile");
// completePopupMenu.show(this, 200, 200);
}
catch (Exception anyExc) {
statusLabel.setText("load aborted");
return;
}
}
void load(String filename) {
BufferedReader br;
try {
br = new BufferedReader(new FileReader(filename));
loadFromFile(br);
}
catch (Exception anyExc) {
statusLabel.setText("load aborted");
return;
}
}
void addLoadLink() {
LoadFileDialog lfd = new LoadFileDialog(frame);
BufferedReader br = null;
Link linkToAdd = null;
try {
br = lfd.getLoadFile("Load Links", "*.knt");
LinkReader lr = new LinkReader(br);
int nLinks = lr.getNLinks();
if (nLinks <= 0) return;
for (int ii = 0; ii < nLinks; ii++) {
linkToAdd = lr.loadLink();
}
}
catch (Exception anyExc) {
statusLabel.setText("load aborted");
return;
}
finally {
try { br.close(); } catch (Exception anyExc) { }
}
paste(linkToAdd);
}
/*
void tangle(String title) {
// title could be "tangle" or "pretzel" or "braid" or "torus"
TangleDialog td = new TangleDialog(frame, title);
if (td.isCancelled()) {
statusLabel.setText(title + " cancelled");
return;
}
int[] tangleSeq = td.getTangleSeq();
if (tangleSeq == null) {
statusLabel.setText("illegal " + title + " sequence");
return;
}
for (int i = 0; i < tangleSeq.length; i++)
System.out.print(tangleSeq[i] + " ");
System.out.println();
addSeries();
if (title.equals("tangle")) ; // link = TangleUnit.makeTangle(tangleSeq);
else if (title.equals("pretzel")) ; // link = TangleUnit.makePretzel(tangleSeq);
else if (title.equals("braid")) {
boolean ok = true;
for (int i = 0; i < tangleSeq.length; i++)
if (tangleSeq[i] == 0) {
ok = false;
break;
}
if (!ok) {
statusLabel.setText("0 not allowed in braid word");
return;
}
// link = TangleUnit.makeBraid(tangleSeq);
}
else if (title.equals("torus")) {
if (tangleSeq.length != 2) {
statusLabel.setText("expect 2 parameters for torus");
return;
}
int n = tangleSeq[0];
int k = tangleSeq[1];
if (n < 1) {
statusLabel.setText("torus: n must be >= 1");
return;
}
if (k < 2) {
statusLabel.setText("torus: k must be >= 2");
return;
}
// link = TangleUnit.makeTorus(n, k);
}
addHistory(link);
currKntName = null;
state = COMPLETE;
setPopupMenu(completePopupMenu);
report("<noname>");
updateDiagram();
}
*/
/*
public BufferedWriter fileToUse(String fileName) {
// check the given file name to see if it already exists
// if not, try to create file with that name
// if it already exists, show a dialog to ask user's
// intention
BufferedWriter bw = null;
String theName = fileName;
ExistsDialog existsDialog = null;
while (bw == null) {
File theFile = new File(theName);
if (theFile.exists() && !overwriteAllFlag) {
existsDialog = new ExistsDialog(frame, ExistsDialog.EXISTS, theName, 200, 150);
if (existsDialog.cancelAllChosen())
cancelAllFlag = true;
if (cancelAllFlag || existsDialog.cancelChosen()) {
return bw; // it's null
}
if (existsDialog.newNameChosen()) {
theName = existsDialog.getName();
continue;
}
if (existsDialog.overwriteAllChosen())
overwriteAllFlag = true;
}
// if we got here, try opening file with theName
boolean sameName = true;
while (sameName) {
try {
bw = new BufferedWriter(new FileWriter(theName));
if (bw == null) throw new Exception("failed to create: " + theName);
break;
}
catch (Exception anyExc) {
existsDialog = new ExistsDialog(frame, ExistsDialog.CREATE_FAIL, theName, 200, 150);
}
if (existsDialog.overwriteChosen()) continue; // retry
if (existsDialog.cancelAllChosen()) cancelAllFlag = true;
if (cancelAllFlag || existsDialog.cancelChosen())
return (BufferedWriter) null;
if (existsDialog.newNameChosen()) {
theName = existsDialog.getName();
sameName = false;
}
} // while (sameName)
} // while (bw == null)
return bw;
}
*/
public BufferedWriter fileToUse(String fileName) throws Exception {
BufferedWriter bw = new BufferedWriter(new FileWriter(fileName));
return bw;
}
/*
void saveLink() {
overwriteAllFlag = cancelAllFlag = false;
String root = "";
if (currKntName != null) {
root = currKntName;
if (root.toUpperCase().endsWith(".KNT"))
root = root.substring(0, root.length()-4);
}
SaveLinkDialog sld = new SaveLinkDialog(frame, SaveLinkDialog.SAVE_LINK, root, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getName();
currKntName = nameRoot;
report(currKntName);
String dyName = sld.getDirectory();
if (!dyName.equals("")) {
if (!dyName.endsWith(File.separator)) dyName += File.separator;
nameRoot = dyName + nameRoot;
}
if (sld.gaussChosen()) {
BufferedWriter gaussFile = fileToUse(nameRoot + ".gss");
if (gaussFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveGauss(gaussFile);
}
if (sld.jenkinsChosen()) {
BufferedWriter jenkinsFile = fileToUse(nameRoot + ".jnk");
if (jenkinsFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveJenkins(jenkinsFile);
}
if (sld.geometricChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + ".knt");
if (kntFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveGeometric(kntFile);
}
if (sld.PLChosen()) {
BufferedWriter plFile = fileToUse(nameRoot + ".pl");
if (plFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePL(plFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + ".ps");
if (psColorFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePS(psColorFile, LinkWriter.COLOR);
}
if (sld.psGreyScaleChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs.ps");
if (psGreyScaleFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePS(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBlackChosen()) {
BufferedWriter psBlackFile = fileToUse(nameRoot + "-bw.ps");
if (psBlackFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePS(psBlackFile, LinkWriter.BLACK);
}
if (sld.uniAlexChosen()) {
BufferedWriter uniAlexFile = fileToUse(nameRoot + "-uni.txt");
if (uniAlexFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveAlex(uniAlexFile, 1); // 1 for univariate
}
if (sld.multiAlexChosen()) {
BufferedWriter multiAlexFile = fileToUse(nameRoot + "-multi.txt");
if (multiAlexFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveAlex(multiAlexFile, 2); // 2 for multivariate
}
}
*/
void saveLink() {
System.out.println("in saveLink");
SaveLinkDialog sld = new SaveLinkDialog(frame, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getNameRoot();
try {
if (sld.geomChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + ".knt");
if (kntFile == null) return;
saveGeometric(kntFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + ".ps");
if (psColorFile == null) return;
savePS(psColorFile, LinkWriter.COLOR);
}
if (sld.psGSChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs.ps");
if (psGreyScaleFile == null) return;
savePS(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBWChosen()) {
BufferedWriter psBlackFile = fileToUse(nameRoot + "-bw.ps");
if (psBlackFile == null) return;
savePS(psBlackFile, LinkWriter.BLACK);
}
if (sld.jenkinsChosen()) {
BufferedWriter jenkinsFile = fileToUse(nameRoot + ".jnk");
if (jenkinsFile == null) { // cancelled
// if (cancelAllFlag) return;
return;
}
else saveJenkins(jenkinsFile);
}
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
}
void saveGeometric(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
System.out.println("about to call saveNLinks");
lw.saveNLinks(1);
System.out.println("after saveNLinks; about to call saveLink nKnots = "
+ link.nKnots);
lw.saveLink(link);
System.out.println("after saveLink");
bw.close();
}
catch (Exception anyExc) {
statusLabel.setText("save aborted");
return;
}
statusLabel.setText("save completed");
}
void savePS(BufferedWriter bw, int colorType) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.writeLine("/Times-Roman findfont 12 scalefont setfont");
lw.writeLine("30 0 translate");
int transIndex = 0;
lw.writeLine("gsave");
lw.writeLine("0.5 0.5 scale");
lw.writeLine(translations[transIndex++]);
lw.saveRoundPS(link, boxWd, boxHt, arcRadius, colorType);
lw.writeLine("grestore");
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PS aborted");
return;
}
statusLabel.setText("save PS completed");
}
/*
void saveSeries() {
overwriteAllFlag = cancelAllFlag = false;
String root = "";
if (currKntName != null) {
root = currKntName;
if (root.toUpperCase().endsWith(".KNT"))
root = root.substring(0, root.length()-4);
}
SaveLinkDialog sld = new SaveLinkDialog(frame, SaveLinkDialog.SAVE_SERIES, root, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getName();
currKntName = nameRoot;
report(currKntName);
String dyName = sld.getDirectory();
if (!dyName.equals("")) {
if (!dyName.endsWith(File.separator)) dyName += File.separator;
nameRoot = dyName + nameRoot;
}
if (sld.geometricChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + "-ser.knt");
if (kntFile == null) {
if (cancelAllFlag) return;
}
else saveGeometricSeries(kntFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + "-ser.ps");
if (psColorFile == null) {
if (cancelAllFlag) return;
}
else savePSSeries(psColorFile, LinkWriter.COLOR);
}
if (sld.psGreyScaleChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs-ser.ps");
if (psGreyScaleFile == null) {
if (cancelAllFlag) return;
}
else savePSSeries(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBlackChosen()) {
BufferedWriter psBlackile = fileToUse(nameRoot + "-bw-ser.ps");
if (psGreyScaleFile == null) {
if (cancelAllFlag) return;
}
else savePSSeries(psBlackFile, LinkWriter.BLACK);
}
}
*/
void saveSeries() {
SaveLinkDialog sld = new SaveLinkDialog(frame, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getNameRoot();
try {
if (sld.geomChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + "-ser.knt");
if (kntFile == null) return;
saveGeometricSeries(kntFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + "-ser.ps");
if (psColorFile == null) return;
savePSSeries(psColorFile, LinkWriter.COLOR);
}
if (sld.psGSChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs-ser.ps");
if (psGreyScaleFile == null) return;
savePSSeries(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBWChosen()) {
BufferedWriter psBlackFile = fileToUse(nameRoot + "-bw-ser.ps");
if (psBlackFile == null) return;
savePSSeries(psBlackFile, LinkWriter.BLACK);
}
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
}
void saveGeometricSeries(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) - start;
lw.saveNLinks(n);
for (int i = 0; i < n; i++) {
lw.saveLink(history[start+i]);
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save series aborted");
return;
}
statusLabel.setText("save series completed");
}
void savePSSeries(BufferedWriter bw, int colorType) {
try {
LinkWriter lw = new LinkWriter(bw);
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) - start;
lw.writeLine("/Times-Roman findfont 12 scalefont setfont");
lw.writeLine("30 0 translate");
int transIndex = 0;
for (int i = 0; i < n; i++) {
lw.writeLine("gsave");
lw.writeLine("0.5 0.5 scale");
lw.writeLine(translations[transIndex++]);
lw.writeLine("0 " + (boxHt+3) + " moveto (#" + (i+1) + ") show");
lw.saveRoundPS(history[start+i], boxWd, boxHt, arcRadius, colorType);
lw.writeLine("grestore");
if (transIndex >= translations.length) {
transIndex = 0;
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PS series aborted");
return;
}
statusLabel.setText("save PS series completed");
}
void saveJenkins(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Jenkins aborted");
return;
}
statusLabel.setText("save Jenkins completed");
}
/*
void saveGauss(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.saveGauss(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Gauss aborted");
return;
}
statusLabel.setText("save Gauss completed");
}
void savePL(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.savePL(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PL aborted");
return;
}
statusLabel.setText("save PL completed");
}
void saveAlex(BufferedWriter bw, int flag) {
try {
link.saveAlex(bw, flag);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Alex aborted");
return;
}
statusLabel.setText("save Alex completed");
}
*/
/*
void save() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Links", "knt");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
lastKntName = sfd.getFileName();
LinkWriter lw = new LinkWriter(bw);
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) - start;
lw.saveNLinks(n);
for (int ii = 0; ii < n; ii++) {
lw.saveLink(history[start+ii]);
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save aborted");
return;
}
statusLabel.setText("save completed");
}
*/
void saveMultiKnt() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Multi", "knt");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
multiKntFilename = sfd.getFileName();
if (!multiKntFilename.toLowerCase().endsWith(".knt"))
throw new Exception("Filename not ending in .knt");
underlinePos = multiKntFilename.lastIndexOf('_');
if (underlinePos < 0) throw new Exception("No _ in filename");
int dotPos = multiKntFilename.length() - 4;
if (underlinePos == dotPos-1)
throw new Exception("_ immediately preceding .knt");
for (int ii = underlinePos+1; ii < dotPos; ii++)
if (!Character.isDigit(multiKntFilename.charAt(ii)))
throw new Exception("Nondigit between _ and .knt");
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save aborted");
return;
}
statusLabel.setText("save completed");
setState(MULTI_KNT, multiKntPopupMenu);
}
void saveCurrentLink(String fileName) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(fileName));
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save aborted " + fileName);
return;
}
statusLabel.setText("save completed " + fileName);
}
void continueMultiKnt() {
setState(MULTI_KNT_UNLINK, cancelPopupMenu);
statusLabel.setText("click knot to unlink");
}
void doneMultiKnt() {
setState(COMPLETE, completePopupMenu);
statusLabel.setText("Save Multi Knt complete");
}
void savePS(boolean bwFlag) {
SaveFileDialog sfd = new SaveFileDialog(frame,
"Save Ps" + (bwFlag ? "_BW" : ""), "ps");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
LinkWriter lw = new LinkWriter(bw);
/* lw.writeLine("%!PS-Adobe-2.0");
lw.writeLine("%%Creator: dvips 5.58 Copyright 1986, 1994 " +
"Radical Eye Software");
lw.writeLine("%%Title: binstr.dvi");
*/
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) -start;
lw.writeLine("/Times-Roman findfont 12 scalefont setfont");
int transIndex = 0;
for (int ii = 0; ii < n; ii++) {
lw.writeLine("gsave");
lw.writeLine(translations[transIndex++]);
lw.writeLine("0 " + (boxHt+3) + " moveto (#" + (ii+1) + ") show");
lw.saveRoundPS(history[start+ii], boxWd, boxHt, arcRadius,
bwFlag ? LinkWriter.BLACK : LinkWriter.COLOR);
lw.writeLine("grestore");
if (transIndex >= translations.length) {
transIndex = 0;
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
}
if (transIndex > 0) {
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PS aborted");
return;
}
statusLabel.setText("save PS completed");
}
void saveJenkins() {
SaveFileDialog sfd = new SaveFileDialog(frame,
"Save Jenkins", ".jnk");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Jenkins aborted");
return;
}
statusLabel.setText("save Jenkins completed");
}
void saveAllJenkins() {
if (link == null) {
statusLabel.setText("save all Jenkins aborted – no link");
return;
}
if (lastKntName == null) {
statusLabel.setText("save all Jenkins aborted – no name");
return;
}
int n = link.getNKnots();
if (n < 2) {
statusLabel.setText("save all Jenkins aborted – one knot");
return;
}
String nameRoot = lastKntName;
if (nameRoot.endsWith(".knt") || nameRoot.endsWith(".KNT"))
nameRoot = nameRoot.substring(0, nameRoot.length()-4);
int numOrientations = 1;
for (int ii = 0; ii < n-1; ii++) numOrientations *= 2;
int curMask = 0;
int prevMask = 0;
Link link1 = new Link(link);
while (curMask < numOrientations) {
int diff = curMask ^ prevMask;
for (int ii = 0; diff != 0; ii++, diff /= 2) {
if ((diff & 1) != 0) link1.reverseKnot(ii);
}
BufferedWriter bw;
try {
bw = new BufferedWriter(new FileWriter(
nameRoot + "-" + curMask + ".jnk"));
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(link1);
bw.close();
bw = new BufferedWriter(new FileWriter(
nameRoot + "-" + curMask + ".knt"));
lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link1);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save all Jenkins aborted");
return;
}
prevMask = curMask;
curMask++;
}
statusLabel.setText("save all Jenkins completed");
}
/*
void saveAlex() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Alex", ".txt");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
link.saveAlex(bw);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save alex aborted");
return;
}
statusLabel.setText("save alex completed");
}
void saveTree() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Tree",
(expandType == HOMFLY) ? "htr" : "btr");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
LinkWriter lw = new LinkWriter(bw);
root.saveTree(lw);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save tree aborted");
return;
}
statusLabel.setText("save tree completed");
}
void saveTreePS() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Tree PS", "ps");
BufferedWriter bw, aw;
try {
bw = sfd.getSaveFile();
String auxName = sfd.getFileName();
int dotPos = auxName.lastIndexOf('.');
if (dotPos >= 0) auxName = auxName.substring(0, dotPos);
auxName += ".aux";
aw = new BufferedWriter(new FileWriter(auxName));
LinkWriter lw = new LinkWriter(bw);
lw.setAuxWriter(aw);
lw.setPSPageSize(pageWidth, pageHeight);
// lw.saveTreePS(scaleFactor);
lw.saveTreePSInit(scaleFactor);
root.saveTreePS(lw, scaleFactor, expandType == HOMFLY);
lw.wrapUp();
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save tree PS aborted");
return;
}
statusLabel.setText("save tree PS completed");
}
void loadTree(int expandType) {
LoadFileDialog lfd = new LoadFileDialog(frame);
BufferedReader br;
try {
br = lfd.getLoadFile("Load Tree",
(expandType == HOMFLY) ? "*.htr" : "*.btr");
LinkReader lr = new LinkReader(br);
currentNode = root = TreeNode.loadTree(lr);
link = currentNode.getCurrentLink();
br.close();
}
catch (Exception anyExc) {
statusLabel.setText("load tree aborted");
return;
}
statusLabel.setText("load tree completed");
this.expandType = expandType;
setState(EXPAND, expandPopupMenu);
}
void getHeading() {
headingDialog = new Dialog(frame, "Node heading", true);
headingTF = new TextField(40);
headingDialog.add(headingTF, BorderLayout.CENTER);
headingTF.addActionListener(this);
headingDialog.setLocation(100, 100);
headingTF.setText(currentNode.getHeading());
headingDialog.pack();
headingDialog.show();
}
*/
void getScaleFactor() {
scaleFactorDialog = new Dialog(frame, "Scale Factor", true);
scaleFactorTF = new TextField(20);
scaleFactorDialog.add(scaleFactorTF, BorderLayout.CENTER);
scaleFactorTF.addActionListener(this);
scaleFactorDialog.setLocation(100, 100);
scaleFactorTF.setText("" + scaleFactor);
scaleFactorDialog.pack();
scaleFactorDialog.setVisible(true);
}
void getPageSize() {
pageSizeDialog = new Dialog(frame, "Page Size", true);
pageSizeTF = new TextField(20);
pageSizeDialog.add(pageSizeTF, BorderLayout.CENTER);
scaleFactorTF.addActionListener(this);
scaleFactorDialog.setLocation(100, 100);
pageSizeDialog.pack();
pageSizeDialog.show();
}
/*
void collectTerms() {
Hashtable ht = new Hashtable();
if (expandType == HOMFLY) {
root.homflyCollectTerms(LPoly2.ONE, ht);
for (Enumeration e = ht.keys(); e.hasMoreElements(); ) {
String s = (String) e.nextElement();
LPoly2 coeff = (LPoly2) ht.get(s);
System.out.print(s + ": ");
coeff.print();
}
}
else {
root.bracketCollectTerms(LPoly.ONE, ht);
for (Enumeration e = ht.keys(); e.hasMoreElements(); ) {
String s1 = (String) e.nextElement();
LPoly coeff1 = (LPoly) ht.get(s1);
System.out.print(s1 + ": ");
coeff1.print();
}
}
}
void cut() {
if (currentNode.currentIsLast() && currentNode.lson != null) {
currentNode.lson = currentNode.rson = null;
currentNode.expandedCrossing = null;
}
else if (currentNode.currentLink > 0) {
currentNode.truncate();
link = currentNode.getCurrentLink();
selectEdge = null;
}
updateDiagram();
}
*/
void firstEdge() {
pushState(FIRST_EDGE, donePopupMenu);
}
void markKnot() {
pushState(MARK_KNOT, donePopupMenu);
}
void doneSelected() {
if (state == REVERSE_KNOT) {
addSeries();
addHistory(reverseOrig, link);
}
selectEdge = null;
popState();
updateInfoAndDiagram();
}
public Dimension getMinimumSize() {
return new Dimension(10, 10);
}
public Dimension getPreferredSize() {
return preferredSize;
}
public void setLink(Link link) {
this.link = link;
}
void alternate() {
if (state != CROSSING) return;
altFlag = true;
setPopupMenu(nonaltPopupMenu);
}
void nonAlternate() {
if (state != CROSSING) return;
altFlag = false;
setPopupMenu(altPopupMenu);
}
public void exitPressed() {
System.exit(0);
}
public void completePressed() {
System.out.println("in completePressed state = " + state);
if (state == BETWEEN_KNOTS) {
if (intersectCt == 0) completeLink();
else {
state = CROSSING; altFlag = false;
setPopupMenu(altPopupMenu);
updateDiagram();
}
}
else if (state == R1I) {
if (nChosenEdges < 1) {
statusLabel.setText("1 edge needed for r1i");
return;
}
else if (nChosenPoints < 2) {
statusLabel.setText("2 points needed for r1i");
return;
}
if (nChosenEdges < 2) chosenEdge2 = chosenEdge1;
try {
link.firstSelectedEdge = chosenEdge1;
link.lastSelectedEdge = chosenEdge2;
Link orig = new Link(link);
link.r1i(chosenEdge1, chosenEdge2, chosenPoints, nChosenPoints);
link.clearSelectedEdges();
addHistory(orig, link);
statusLabel.setText("toggle crossing or confirm");
}
catch (Exception anyExc) {
link.clearSelectedEdges();
statusLabel.setText(anyExc.getMessage());
return;
}
state = R1I_CROSSING;
setPopupMenu(confirmPopupMenu);
updateDiagram();
}
else if (state == MAC) {
System.out.println("in completePressed() state is MAC #chosen edges = "
+ nChosenEdges);
if (nChosenEdges < 1) {
statusLabel.setText("1 edge needed for mac");
return;
}
if (nChosenEdges < 2) chosenEdge2 = chosenEdge1;
try {
link.firstSelectedEdge = chosenEdge1;
link.lastSelectedEdge = chosenEdge2;
System.out.println("about to construct copy of link");
Link orig = new Link(link);
System.out.println("about to call Link.mac");
link.mac(chosenEdge1, chosenEdge2, chosenPoints, nChosenPoints);
System.out.println("back from Link.mac");
link.clearSelectedEdges();
addHistory(orig, link);
}
catch (Exception anyExc) {
link.clearSelectedEdges();
statusLabel.setText(anyExc.getMessage());
return;
}
if (link.macCompleted()) {
statusLabel.setText("mac completed");
popState();
}
else {
statusLabel.setText("toggle crossing or confirm");
state = MAC_CROSSING;
setPopupMenu(confirmPopupMenu);
}
updateInfoAndDiagram();
}
}
public void completeVert(){
if (nChosenEdges == 0 || nChosenPoints < 1) {
statusLabel.setText("complete | not applicable");
return;
}
Point p = ( (nChosenEdges == 1) ? chosenEdge1 : chosenEdge2 ).
getOutPt().getLocation();
p = cornerVert(lastPtLoc, p);
chosenPoints[nChosenPoints++] = p;
completePressed();
}
public void completeHoriz() {
if (nChosenEdges == 0 || nChosenPoints < 1) {
statusLabel.setText("complete - not applicable");
return;
}
Point p = ( (nChosenEdges == 1) ? chosenEdge1 : chosenEdge2 ).
getOutPt().getLocation();
p = cornerHoriz(lastPtLoc, p);
chosenPoints[nChosenPoints++] = p;
completePressed();
}
public void cancelPressed() {
switch (state) {
case COMPLETE: case R1I: // case R2I: case R3: case STRAIGHTEN:
case MAC: case UNLINK_KNOT: case ROTATE:
break;
case UNLINK_CONFIRM: case ROTATE_CONFIRM: case STRAIGHTEN:
case REVERSE_CONFIRM: case REFLECT_CONFIRM:
link = history[(--nLinks) - 1];
break;
case RECT_UNKNOT: case DUP_KNOT_CHOOSE:
cancelKnot();
return;
case CLIP_RECT:
rectStage = NONE;
setState(EXPAND, expandPopupMenu);
return;
case MULTI_KNT_UNLINK:
statusLabel.setText("Save Multi Knt cancelled");
setState(COMPLETE, completePopupMenu);
return;
case MULTI_KNT_CONFIRM:
link = history[(--nLinks) - 1];
statusLabel.setText("click knot to unlink");
setState(MULTI_KNT_UNLINK, cancelPopupMenu);
selectEdge = null;
updateDiagram();
return;
/*
case ITERATE:
UnitLink ul = new UnitLink(link);
Iterate.printUnitLink(ul);
rectStage = NONE;
statusLabel.setText("complete");
setState(COMPLETE, completePopupMenu);
updateDiagram();
return;
*/
}
popState();
selectEdge = null;
updateDiagram();
statusLabel.setText("");
}
public void tricolor() {
if (link.isSplit()) {
statusLabel.setText("link split");
return;
}
else if (!link.tricolorable()) {
statusLabel.setText("link not tricolorable");
return;
}
pushState(TRICOLOR, cancelPopupMenu);
updateDiagram();
statusLabel.setText("tricolor: " + link.getNStrands() + " strands");
cancelPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
/*
public void skeleton() {
skeletonCopy = link.makeSkeletonCopy();
state = SKELETON;
setPopupMenu(cancelPopupMenu);
updateDiagram();
cancelPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
public void simplify() {
skeletonCopy = link.makeSkeletonCopy();
skeletonCopy.simplifyIAndII();
state = SIMPLIFY;
setPopupMenu(cancelPopupMenu);
updateDiagram();
cancelPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
public void bktPoly() {
skeletonCopy = link.makeSkeletonCopy();
LPoly p = Link.bktPoly(skeletonCopy);
System.out.println("bkt poly:");
p.print();
}
public void fBktPoly() {
skeletonCopy = link.makeSkeletonCopy();
LPoly p = Link.fBktPoly(skeletonCopy);
System.out.println("fbkt poly:");
p.print();
}
public void homfly() {
Date start = new Date();
skeletonCopy = link.makeSkeletonCopy();
GLink gSkeletonCopy = new GLink(skeletonCopy);
LPoly2 p = gSkeletonCopy.homfly_sta();
System.out.println("homfly:");
p.print();
System.out.println("time (ms): " +
((new Date()).getTime() - start.getTime()) );
}
public void KL() {
Date start = new Date();
skeletonCopy = link.makeSkeletonCopy();
GLink gSkeletonCopy = new GLink(skeletonCopy);
LPoly2 p = gSkeletonCopy.KL_sta();
System.out.println("Kauffman-L:");
p.print();
System.out.println("time (ms): " +
((new Date()).getTime() - start.getTime()) );
}
public void Kauffman_unoriented() {
Date start = new Date();
GLink g = new GLink(link);
LPoly2 p = g.Kauffman_unoriented();
System.out.println("Kauffman-unoriented:");
p.print();
System.out.println("time (ms): " +
((new Date()).getTime() - start.getTime()) );
}
*/
void setState(int newState, PopupMenu newPopupMenu) {
state = newState;
setPopupMenu(newPopupMenu);
updateDiagram();
if (newState == MULTI_KNT || newState == REVERSE_CONFIRM)
newPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
void pushState(int newState, PopupMenu newPopupMenu) {
oldState = state;
oldPopupMenu = currentPopupMenu;
setState(newState, newPopupMenu);
}
void popState() {
setState(oldState, oldPopupMenu);
}
/*
void joinHorV(Point p) {
XOPt xp = link.findXOPt(p);
if (xp != null) {
Link orig = new Link(link);
link.print();
link = link.makeSkeletonCopy();
System.out.println("skeletonized");
link.print();
System.out.println("***");
xp = link.findXOPt(p);
if (state == JOIN_VERTICAL) link.joinVertical(xp);
else link.joinHorizontal(xp);
link.print();
history[nLinks-1] = orig;
addHistory(link);
}
else{
statusLabel.setText("point clicked not a crossing");
}
}
void nullify(Point p) {
XOPt xp = link.findXOPt(p);
if (xp != null) {
Link orig = new Link(link);
xp = link.findXOPt(p);
link.nullify(xp);
addHistory(orig, link);
}
else {
statusLabel.setText("point clicked not a crossing");
}
}
void alex() {
try {
int[] res = link.alex();
for (int ii = 0; ii < res.length; ii++)
System.out.print(res[ii] + " ");
System.out.println();
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
}
}
void printMapleSeq(int[] vec) {
System.out.print("[" + vec[0]);
for (int i = 1; i < vec.length; i++)
System.out.print("," + vec[i]);
System.out.print("]");
}
*/
void wirtinger() {
/*
try {
int[][] wirt = link.getWirtinger();
System.out.println("[");
for (int i = 0; i < wirt.length-1; i++) {
printMapleSeq(wirt[i]);
System.out.println(",");
}
printMapleSeq(wirt[wirt.length-1]);
System.out.println();
System.out.println("]");
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
}
*/
}
/*
void startExpand(int expandType) {
// saveTree();
// addSeries();
// addHistory(currentNode.getCurrentLink());
// history[nLinks-1].clearSelectedEdges();
// link = history[nLinks-1];
currentNode = root = new TreeNode((TreeNode) null, link);
selectEdge = null;
this.expandType = expandType;
setState(EXPAND, expandPopupMenu);
}
void quitExpand() {
saveTree();
addSeries();
addHistory(currentNode.getCurrentLink());
history[nLinks-1].clearSelectedEdges();
link = history[nLinks-1];
currentNode = root = null;
selectEdge = null;
setState(COMPLETE, completePopupMenu);
}
void forward() {
currentNode.forward();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void backward() {
currentNode.backward();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void firstInTreeNode() {
currentNode.first();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void lastInTreeNode() {
currentNode.last();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void upTree() {
TreeNode res = currentNode.up();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void downTree() {
TreeNode res = currentNode.down();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void sibling() {
TreeNode res = currentNode.sibling();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void nextNode() {
TreeNode res = currentNode.next();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void expand() {
if (!currentNode.okToExpand()) {
statusLabel.setText("can't expand");
return;
}
pushState(EXPAND_CROSSING, cancelPopupMenu);
}
void expandCrossing(Point p) {
XOPt xp = link.findXOPt(p);
if (xp == null) {
statusLabel.setText("point clicked is not a crossing");
}
else if (expandType == HOMFLY) {
Link switched = new Link(link);
xp = switched.findXOPt(p);
xp.toggle();
switched.wrapUp();
Link nullified = new Link(link);
xp = nullified.findXOPt(p);
currentNode.expand(p, switched, nullified);
downTree();
setState(EXPAND, expandPopupMenu);
}
else {
Link vert = new Link(link);
xp = vert.findXOPt(p);
vert.joinVertical(xp);
Link horiz = new Link(link);
xp = horiz.findXOPt(p);
horiz.joinHorizontal(xp);
currentNode.expand(p, vert, horiz);
downTree();
setState(EXPAND, expandPopupMenu);
}
}
*/
void toggleGrid() {
gridOn = !gridOn;
updateDiagram();
}
void cancelKnot() {
nChosenPoints = 0;
state = BETWEEN_KNOTS;
setPopupMenu(betweenKnotsPopupMenu);
updateDiagram();
statusLabel.setText("between knots");
}
void completeLink() {
System.out.println("in completeLink()");
state = COMPLETE;
if (link != null) {
System.out.println("about to call link.wrapUp()");
link.wrapUp();
System.out.println("after call to link.wrapUp()");
// statusLabel.setText("link completed");
report("<noname>");
}
setPopupMenu(completePopupMenu);
System.out.println("after setting to completePopupMenu");
updateDiagram();
}
void completeKnot() {
System.out.println("in completeKnot state = " + state);
state = BETWEEN_KNOTS;
setPopupMenu(betweenKnotsPopupMenu);
nChosenEdges = 0;
nChosenPoints = 0;
knotEdgeCt = 0;
startPt = null;
lastEdge = null;
selectEdge = null;
statusLabel.setText("between knots");
}
public void confirmPressed() {
System.out.println("state = " + state);
String confirmMsg = "";
switch (state) {
case R1I_CROSSING: case MAC_CROSSING:
case UNLINK_CONFIRM: case ROTATE_CONFIRM: case REVERSE_CONFIRM: case REVERSE_KNOT:
switch (state) {
case R1I_CROSSING:
confirmMsg = "r1i performed"; break;
case MAC_CROSSING:
confirmMsg = "mac performed"; break;
case UNLINK_CONFIRM:
addSeries();
addHistory(reverseOrig, link);
confirmMsg = "unlink performed"; break;
case ROTATE_CONFIRM:
confirmMsg = "rotate performed"; break;
case REVERSE_CONFIRM: case REVERSE_KNOT:
addSeries();
addHistory(reverseOrig, link);
confirmMsg = "reverse performed";
selectEdge = null;
break;
}
popState();
statusLabel.setText(confirmMsg);
break;
case RECT_UNKNOT:
if (rectStage != PRESENT || rectWidth < MIN_LENGTH ||
rectHeight < MIN_LENGTH) {
statusLabel.setText("Rect unknot nonexistent or too small");
return;
}
Point[] pa = new Point[5];
pa[0] = new Point(rectLeft, rectTop);
pa[1] = new Point(rectLeft, rectTop+rectHeight);
pa[2] = new Point(rectLeft+rectWidth, rectTop+rectHeight);
pa[3] = new Point(rectLeft+rectWidth, rectTop);
pa[4] = null;
state = VERTEX;
System.out.println("calling addVertices for RECT_UNKNOT: pa.length = "
+ pa.length);
addVertices(pa);
return;
case CLIP_RECT:
if (rectStage != PRESENT || rectWidth < MIN_LENGTH ||
rectHeight < MIN_LENGTH) {
statusLabel.setText("Rect unknot nonexistent or too small");
return;
}
Point[] pa1 = new Point[2];
pa1[0] = new Point(rectLeft, rectTop);
pa1[1] = new Point(rectLeft+rectWidth, rectTop+rectHeight);
// currentNode.setClipRect(pa1);
rectStage = NONE;
setState(EXPAND, expandPopupMenu);
return;
case CROSSING:
completeLink();
return;
case MULTI_KNT_CONFIRM:
int fileNameLen = multiKntFilename.length();
int seqNum = Integer.parseInt(
multiKntFilename.substring(underlinePos+1,
fileNameLen-4))-1;
multiKntFilename = multiKntFilename.substring(0, underlinePos+1)
+ seqNum + multiKntFilename.substring(fileNameLen-4);
saveCurrentLink(multiKntFilename);
statusLabel.setText("saved in " + multiKntFilename);
setState(MULTI_KNT, multiKntPopupMenu);
return;
default:
statusLabel.setText("not expecting crossings confirmation");
return;
}
updateInfoAndDiagram();
}
/*
void doIterate() {
rectStage = NONE;
int iterIndex = 0;
IterDialog iterDlg = new IterDialog(frame, lastPtLoc.x+20, lastPtLoc.y+20);
if (!iterDlg.okayed()) {
statusLabel.setText("Iterate aborted");
setState(COMPLETE, completePopupMenu);
updateDiagram();
return;
}
if (iterDlg.hfMatrixChosen()) { // makeIterativeMatrix()
makeLeftIterativeMatrix_GP_p8(true, null); // first param is oriented
}
if (iterDlg.klMatrixChosen()) { // makeIterativeMatrix()
makeLeftIterativeMatrix_GP_p8(false, null); // first param is oriented
}
try {
link = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
boolean geometric = iterDlg.geometricChosen();
boolean gauss = iterDlg.gaussChosen();
boolean jenkins = iterDlg.jenkinsChosen();
boolean pl = iterDlg.plChosen();
boolean hfSeries = iterDlg.hfSeriesChosen();
boolean klSeries = iterDlg.klSeriesChosen();
if (gauss || jenkins || geometric || pl) {
int lbound = iterDlg.getLbound();
int ubound = iterDlg.getUbound();
try {
for (iterIndex = lbound; iterIndex <= ubound; iterIndex++)
Iterate.makeKnt(iterIndex, gauss, jenkins, geometric, pl);
statusLabel.setText("ITERATE completed");
}
catch (Exception anyExc) {
statusLabel.setText(iterIndex + ": " + anyExc.getMessage());
}
}
Link hfSeriesLink = null;
Link klSeriesLink = null;
int hfCount = 0, klCount = 0;
int newLeft = 0, newRight = 0;
String kntName = currKntName;
if (currKntName.endsWith(".knt"))
kntName = kntName.substring(0, kntName.length()-4);
try {
if (hfSeries || klSeries) {
newLeft = rectLeft - (3*ITERATE_DX)/5;
newRight = newLeft + ITERATE_DX/5;
}
if (hfSeries) {
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
Iterate.getLeftIterScheme_GG(true, (Hashtable)null, true);
// to get the standard left ends
hfCount = iterDlg.getHfCount();
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
hfSeriesLink = Iterate.createKnt(hfCount, true);
}
if (klSeries) {
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
Iterate.getLeftIterScheme_GG(false, (Hashtable) null, true);
// to get the standard left ends
klCount = iterDlg.getKlCount();
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
klSeriesLink = Iterate.createKnt(klCount, true);
}
if (hfSeries) {
UnitLink hfIterLink = new UnitLink(hfSeriesLink);
Iterate.checkFitness(hfIterLink, newLeft, newRight,
ITERATE_DX/5, ITERATE_GAP, kntName);
savePSLeftBases(kntName+"-"+hfCount, true, (Hashtable) null);
// oriented permuteTable
}
if (klSeries) {
UnitLink klIterLink = new UnitLink(klSeriesLink);
Iterate.checkFitness(hfIterLink, newLeft, newRight,
ITERATE_DX/5, ITERATE_GAP, kntName);
savePSLeftBases(kntName+"-"+klCount, false, (Hashtable) null);
// oriented permuteTable
}
}
catch(Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("series: " + anyExc.getMessage());
setState(COMPLETE, completePopupMenu);
updateDiagram();
}
}
boolean same(LPoly2[] A, LPoly2[] B) {
if (A.length != B.length) return false;
for (int i = 0; i < A.length; i++)
if (!A[i].equals(B[i])) return false;
return true;
}
static void makeLeftIterativeMatrix_G(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_G(oriented, permuteTable);
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_G(oriented, permuteTable);
try {
PrintWriter pw = Iterate.getOutfile("G" + (GLink.simplifyFlag ? "S" : "")
+ (GLink.wrongFlag ? "W" : "") + "-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_G (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GG(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GG(oriented, permuteTable, false); // use old simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, false); // use old simplify
try {
PrintWriter pw = Iterate.getOutfile("GG" + (GLink.simplifyFlag ? "S" : "")
+ (GLink.wrongFlag ? "W" : "") + "-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GG (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GN(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GG(oriented, permuteTable, true); // use new simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, true); // use new simplify
try {
PrintWriter pw = Iterate.getOutfile("GN-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GN (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GP(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GP(oriented, permuteTable, true); // use new simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, true); // use new simplify
try {
PrintWriter pw = Iterate.getOutfile("GP-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GP (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GP_p8(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GP_p8(oriented, permuteTable); // use new simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, true); // use new simplify
try {
PrintWriter pw = Iterate.getOutfile("GP8" + (GLink.p8aFlag ? "a" : "") + "-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GP (oriented = " + oriented + ") failed");
}
}
static void compareLeftIterativeMatrix_GP_p8(boolean oriented, Hashtable permuteTable) {
Vector v1 = Iterate.getLeftIterScheme_GP_p8(oriented, permuteTable);
Vector v2 = Iterate.getLeftIterScheme_GG(oriented, permuteTable, true);
LPoly2[][] matx1 = (LPoly2[][]) v1.elementAt(1);
LPoly2[][] matx2 = (LPoly2[][]) v2.elementAt(1);
System.out.println(LPoly2.matrixEquals(matx1, matx2) ? "equal" : "not equal");
}
static void makeLeftBases(boolean oriented) {
Vector v = Iterate.getLeftBases(oriented, (Hashtable) null);
// v.elementAt(0) is a Vector of maps
for (int i = 1, lastI = v.size(); i < lastI; i++) {
Link link = (Link) v.elementAt(i);
System.out.println("#comps = " + link.getNKnots());
BufferedWriter bw;
try {
bw = new BufferedWriter(new FileWriter("H1-" + i + ".knt"));
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link);
bw.close();
}
catch (Exception anyExc) {
return;
}
}
}
static void savePSLeftBases(String name, boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftBases(orineted, permuteTable);
int n = v.size();
if (n <= 1) return;
Vector maps = (Vector) v.elementAt(0);
String[] translations = {"80 600 translate", "80 360 translate", "80 120 translate",};
BufferedWriter bw = null;
try {
bw = new BufferedWriter(name + "-" + (oriented ? "hf" : "kl") + "series.ps");
LinkWriter lw = new LinkWriter(bw);
lw.writeLine("%!PS-Adobe-2.0:");
lw.writeLine("%%Creator: dvips 5.58 Copyright 1986, 1994 " +
"Radical Eye Software");
lw.writeLine("%%Title: binstr.dvi");
int perPage = translations.length;
lw.writeLine("%%Pages: " + ((n-1+perPage-1)/perPage));
lw.writeLine("%%PageOrder: Ascend");
lw.writeLine("%%BoundingBox: 0 0 612 792");
lw.writeLine("%%EndComments");
lw.writeLine("%DVIPSCommandLine: dvips binstr");
lw.writeLine("%DVIPSParameters: dpi=600, comments removed");
lw.writeLine("%DVIPSSource: TeX output 1997.08.26:1535");
lw.writeLine("%%BeginProcSet: tex.pro");
lw.writeLine("%%EndProcSet");
lw.writeLine("%%BeginSetup");
int pageNumber = 1;
lw.writeLine("/Times-Roman findfont 18 scalefont setfont");
int transIndex = 0;
for (int i = 1; i < n; i++) {
if (transIndex == 0) {
lw.writeLine("%%Page: " + pageNumber + " " + pageNumber);
pageNumber++;
}
lw.writeLine("gsave");
lw.writeLine(translations[transIndex++]);
lw.writeLine("0.5 0.5 scale");
lw.writeLine("0 " + (boxHt+15) + " moveto (#" + i + " ("
+ Util.getPairing(Util.renumber(
Util.getIntArray((String) maps.elementAt(i-1))))
+ ")) show");
lw.saveRoundPS((Link) v.elementAt(i), boxWd, boxHt, arcRadius, LinkWriter.COLOR);
// bwFlag
lw.writeLine("grestore");
if (transIndex >= translations.length) {
transIndex = 0;
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
}
if (transIndex > 0) {
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
bw.close();
}
catch (Exception anyExc) {
System.out.println("save PS-series aborted");
System.out.println(anyExc);
return;
}
}
*/
double distance(int x1, int y1, int x2, int y2) {
return Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
public void r1i() {
if (state != COMPLETE && state != EXPAND) {
statusLabel.setText("r1i not allowed on incomplete link");
return;
}
// else if (state == EXPAND && !currentNode.okToSimplify()) {
// statusLabel.setText("r1i not allowed in this link");
// return;
// }
nChosenEdges = 0;
nChosenPoints = 0;
pickMode = EDGES_MODE;
pushState(R1I, pickPopupMenu);
statusLabel.setText("r1i/edges");
}
public void mac() {
System.out.println("in mac() state = " + state);
if (state != COMPLETE && state != EXPAND) {
statusLabel.setText("mac not allowed on incomplete link");
return;
}
// else if (state == EXPAND && !currentNode.okToSimplify()) {
// statusLabel.setText("mac not allowed in this link");
// return;
// }
nChosenEdges = 0;
nChosenPoints = 0;
pickMode = EDGES_MODE;
pushState(MAC, pickPopupMenu);
System.out.println("in mac() after pushState state = " + state);
statusLabel.setText("mac/edges");
}
public void r1d() {
if (state != COMPLETE && state != EXPAND) {
statusLabel.setText("r1d not allowed on incomplete link");
return;
}
// else if (state == EXPAND && !currentNode.okToSimplify()) {
// statusLabel.setText("r1d not allowed in this link");
// return;
// }
else if (selectEdge == null) {
statusLabel.setText("no arc chosen for r1d");
return;
}
try {
link.firstSelectedEdge = selectEdge;
Edge e = selectEdge;
while (e.getOutPt() instanceof NXPt) e = e.getNext();
link.lastSelectedEdge = e;
Link orig = new Link(link);
link.r1d(selectEdge);
link.clearSelectedEdges();
addHistory(orig, link);
}
catch (Exception anyExc) {
link.clearSelectedEdges();
statusLabel.setText(anyExc.getMessage());
return;
}
statusLabel.setText("r1d performed");
selectEdge = null;
updateDiagram();
}
public void edges() {
pickMode = EDGES_MODE;
if (state == MAC) statusLabel.setText("mac/edges");
else statusLabel.setText("r1i/edges");
nChosenPoints = 0;
updateDiagram();
}
public void points() {
if (nChosenEdges == 0) {
statusLabel.setText("must choose edges first");
return;
}
pickMode = POINTS_MODE;
if (state == MAC) statusLabel.setText("mac/points");
else statusLabel.setText("r1i/points");
lastPtLoc = chosenEdge1.getInPt().getLocation();
updateDiagram();
}
/*
public void zigzag() {
// state must be VERTEX
ZZDialog zzDlg = new ZZDialog(frame, lastPtLoc.x+20, lastPtLoc.y+20);
try {
Point[] pa = zzDlg.getPoints(lastPtLoc.x, lastPtLoc.y);
for (int ii = 0; ii < pa.length; ii++) {
if (nChosenPoints < chosenPoints.length) {
lastPtLoc = chosenPoints[nChosenPoints++] = pa[ii];
}
else {
statusLabel.setText("too many points – ignored");
break;
}
}
updateDiagram();
}
catch (Exception anyExc) {
statusLabel.setText("zigzag aborted");
}
}
*/
public void undo() {
if (state == VERTEX) {
nChosenPoints--;
if (nChosenPoints == 0) {
state = BETWEEN_KNOTS;
setPopupMenu(betweenKnotsPopupMenu);
statusLabel.setText("between knots");
}
else lastPtLoc = chosenPoints[nChosenPoints-1];
updateDiagram();
return;
}
if (state != MAC && state != R1I || pickMode != POINTS_MODE) {
statusLabel.setText("can only undo points");
return;
}
if (nChosenPoints > 0) {
nChosenPoints--;
if (nChosenPoints > 0) lastPtLoc = chosenPoints[nChosenPoints-1];
else lastPtLoc = chosenEdge1.getInPt().getLocation();
updateDiagram();
}
}
public void flip() {
if (nChosenPoints > 1) {
Edge temp = chosenEdge1;
chosenEdge1 = chosenEdge2;
chosenEdge2 = temp;
updateDiagram();
}
}
Edge findEdge(Point p) {
return findEdge(link, p);
}
Edge findEdge(Link link, Point p) {
int nKnots = link.getNKnots();
for (int knotId = 0; knotId < nKnots; knotId++) {
Edge e = link.getFirstEdge(knotId);
Edge firstEdge = e;
int x = p.x, y = p.y;
do {
Point p1 = e.getInPt().getLocation();
int x1 = p1.x, y1 = p1.y;
Point p2 = e.getOutPt().getLocation();
int x2 = p2.x, y2 = p2.y;
double edgeLen = distance(x1, y1, x2, y2);
double angle = -e.getTrueAngle()*Math.PI/180;
double dx = (x-x1)*Math.cos(angle) + (y-y1)*Math.sin(-angle);
double dy = (x-x1)*Math.sin(angle) + (y-y1)*Math.cos(angle);
if (0 <= dx && dx <= edgeLen && Math.abs(dy) <= tolerance)
return e;
e = e.getNext();
} while (e != firstEdge);
}
return (Edge) null;
}
void addVertex(Point p) {
pa1[0] = p;
System.out.println("calling addVertices from addVertex");
addVertices(pa1);
}
Point cornerVert(Point p1, Point p2) {
// the corner if we go from p1 to p2, vertically first
return new Point(p1.x, p2.y);
}
Point cornerHoriz(Point p1, Point p2) {
// the corner if we go from p1 to p2, horizontally first
return new Point(p2.x, p1.y);
}
void closeKnot() {
System.out.print("calling addvertices from closeKnot: ");
System.out.println("nChosenPoints = " + nChosenPoints + " knotEdgeCt = " +
knotEdgeCt + " intersectCt = " + intersectCt);
addVertices(chosenPoints, nChosenPoints);
addVertex((Point) null);
state = BETWEEN_KNOTS;
System.out.println("nChosenPoints = " + nChosenPoints + " knotEdgeCt = " +
knotEdgeCt + " intersectCt = " + intersectCt);
}
void closeVert() {
if (state != VERTEX || nChosenPoints < 2) {
statusLabel.setText("no knot to close");
return;
}
if (nChosenPoints < chosenPoints.length) {
chosenPoints[nChosenPoints++] =
cornerVert(lastPtLoc, chosenPoints[0]);
closeKnot();
}
}
void closeHoriz() {
if (state != VERTEX || nChosenPoints < 2) {
statusLabel.setText("no knot to close");
return;
}
if (nChosenPoints < chosenPoints.length) {
chosenPoints[nChosenPoints++] =
cornerHoriz(lastPtLoc, chosenPoints[0]);
closeKnot();
}
}
void addVertices(Point[] pa) {
System.out.println("calling addVertices from addVertices pa.length = " +
pa.length);
addVertices(pa, pa.length);
}
void addVertices(Point[] pa, int nPoints) {
System.out.println("in addVertices(Point[], int): state = " + state +
" nPoints = " + nPoints + " knotEdgeCt = " + knotEdgeCt);
Edge firstNewEdge = null;
int nNewEdges = 0;
boolean closeKnotFlag = false;
for (int kk = 0; kk < nPoints; kk++) {
Point p = pa[kk];
// p is null to close the link
if (p == null) {
closeKnotFlag = true;
if (state != VERTEX) {
statusLabel.setText("vertex not expected");
return;
}
if (knotEdgeCt < 2) {
statusLabel.setText("can't close link yet");
return;
}
newPt = startPt;
p = newPt.getLocation();
}
else newPt = new NXPt(p.x, p.y, link, knotId);
// lastPt = newPt;
if (startPt == null) {
startPt = lastPt = newPt;
knotId = link.newKnot();
continue;
}
if (closeKnotFlag || kk > 0) {
// if (lastPt.equals(startPt)) {
// statusLabel.setText("loop not allowed");
// return;
// }
if (p != null) { outx = p.x; outy = p.y; }
p = lastPt.getLocation();
inx = p.x; iny = p.y;
link.appendEdge(knotId,
newEdge = new Edge(lastPt, newPt, link, knotId));
if (link.firstEdge[knotId] == null) link.firstEdge[knotId] = newEdge;
lastPt.setOutEdge(newEdge);
newPt.setInEdge(newEdge);
lastEdge = newEdge;
if (firstNewEdge == null) firstNewEdge = newEdge;
knotEdgeCt++; linkEdgeCt++; nNewEdges++;
if (linkEdgeCt > linkEdgeMax) {
linkEdgeMax *= 2;
createArrays();
}
}
lastPt = newPt;
}
// if (lastPt.equals(startPt)) {
// System.out.println("lastPt.equals(startPt)");
// statusLabel.setText("loop not allowed");
// return;
// }
if (nPoints > 1 || closeKnotFlag) {
System.out.println("calling handleCrossings nNewEdges = " + nNewEdges);
handleCrossings(firstNewEdge, nNewEdges, link.nKnots-1, false);
}
else System.out.println("skipping handleCrossings");
if (knotEdgeCt > 2 && newPt == startPt)
completeKnot();
updateDiagram();
}
void handleCrossings(Edge firstNewEdge, int nNewEdges, int nOrigKnots,
boolean suppressSelfCrossingsCheck) {
System.out.println("in handleCrossings nNewEdges = " + nNewEdges +
" nOrigKnots = " + nOrigKnots);
Edge newEdge = firstNewEdge;
knotId = newEdge.getKnotId();
int inx, iny, outx, outy;
for (int kk = 0; kk < nNewEdges; kk++) {
Point p = newEdge.getInPt().getLocation();
inx = p.x; iny = p.y;
p = newEdge.getOutPt().getLocation();
outx = p.x; outy = p.y;
Edge nextEdge = newEdge.getNext();
Edge e = link.getFirstEdge(knotId);
int oldIntersectCt = intersectCt;
if (!suppressSelfCrossingsCheck) {
while (e != newEdge) {
System.out.print(e.toString() + " and " + newEdge.toString() + " ");
double t = newEdge.intersect(e);
System.out.println("t = " + t);
if (0 < t && t < 1) {
ta[intersectCt] = t; ea[intersectCt] = e;
intersectCt++;
}
e = e.getNext();
}
}
for (int ii = 0; ii < nOrigKnots; ii++) {
Edge eStart = link.getFirstEdge(ii);
e = eStart;
do {
double t = newEdge.intersect(e);
if (0 < t && t < 1) {
ta[intersectCt] = t;
ea[intersectCt] = e;
intersectCt++;
}
e = e.getNext();
} while (e != eStart);
}
if (intersectCt > oldIntersectCt) {
// sort the ta and ea arrays, by the ta values
for (int ii = intersectCt-1; ii > oldIntersectCt; ii--)
for (int j = oldIntersectCt; j < ii; j++)
if (ta[j] < ta[j+1]) {
double tempT = ta[j];
ta[j] = ta[j+1];
ta[j+1] = tempT;
Edge tempE = ea[j];
ea[j] = ea[j+1];
ea[j+1] = tempE;
}
// assume all crossings are "overcrossings"
for (int ii = oldIntersectCt; ii < intersectCt; ii++) {
double t = ta[ii];
int x = (int) Math.round((1-t)*inx+t*outx);
int y = (int) Math.round((1-t)*iny+t*outy);
xptx[ii] = x; xpty[ii] = y;
XOPt thisMidPt = new XOPt(x, y, link, knotId, ea[ii].getKnotId());
xoa[ii] = thisMidPt;
System.out.println("in handleCrossings ii = " + ii + " xoa[ii] = " +
xoa[ii].encoding());
newEdge.splitEdge(thisMidPt);
ea[ii].splitEdge(thisMidPt.getMate());
linkEdgeCt += 2;
knotEdgeCt++;
if (ea[ii].getKnotId() == knotId) knotEdgeCt++;
newEdge = newEdge.getNext();
}
}
newEdge = nextEdge;
}
}
void handleCrossings(int firstNewKnotId, int nOrigKnots) {
for (int knotId = firstNewKnotId; knotId < link.getNKnots(); knotId++) {
Edge newEdge = link.getFirstEdge(knotId);
int nEdges = link.getNEdges(knotId);
handleCrossings(newEdge, nEdges, nOrigKnots, true);
}
}
boolean addNewEdge(Edge newEdge, Vector pts, Vector edges,
int tolerance) {
edges.addElement(newEdge);
knotEdgeCt = edges.size();
return true;
}
void completeDupKnot(int knotId, int nOrigKnots) {
Edge e = link.getFirstEdge(knotId);
Edge e1 = e;
int nEdges = 0;
do {
nEdges++;
e = e.getNext();
} while (e != e1);
linkEdgeCt += nEdges; knotEdgeCt = nEdges;
if (linkEdgeCt > linkEdgeMax) {
linkEdgeMax *= 2;
createArrays();
}
// load the XOPts of the selfcrossings into the xptx, xpty
// and xoa arrays
XPt p = link.getFirstXPt(knotId);
if (p != null) {
XPt p1 = p;
do {
if (p instanceof XOPt) {
Point loc = p.getLocation();
xptx[intersectCt] = loc.x;
xpty[intersectCt] = loc.y;
xoa[intersectCt] = (XOPt) p;
intersectCt++;
}
p = p.getNext();
} while (p != p1);
}
handleCrossings(link.getFirstEdge(knotId), nEdges, nOrigKnots, true);
}
void completeDupKnot() {
for (int k = nOldKnots; k < link.nKnots; k++)
completeDupKnot(k, nOldKnots);
completeKnot();
updateDiagram();
}
int findCrossing(int x, int y) {
int squaredRadius = radius*radius;
for (int ii = 0; ii < intersectCt; ii++)
if ((x-xptx[ii])*(x-xptx[ii]) + (y-xpty[ii])*(y-xpty[ii]) < squaredRadius)
return ii;
return -1;
}
void toggleCrossing(Point p) {
int crossingIndex = findCrossing(p.x, p.y);
if (crossingIndex >= 0) {
xoa[crossingIndex].toggle();
statusLabel.setText("toggle crossing or confirm");
}
else {
statusLabel.setText("point clicked not a crossing");
}
}
void setAlt(Point p) {
int crossingIndex = findCrossing(p.x, p.y);
if (crossingIndex >= 0) link.setAlt(xoa[crossingIndex]);
}
Point correctPoint(Point p1, Point p2) {
// if the line from p1 to p2 is close to being vertical/horizontal,
// return a Point p3 that makes the line from p3 to p2 exactly
// vertical/horizontal
if (Math.abs(p1.x-p2.x) < RECT_TOLERANCE)
return new Point(p2.x, p1.y);
else if (Math.abs(p1.y-p2.y) < RECT_TOLERANCE)
return new Point(p1.x, p2.y);
else return p1;
}
void tentativeAddHistory(Link orig, int nextState) {
history[nLinks-1] = orig;
addHistory(link);
statusLabel.setText("confirm or cancel");
state = nextState;
setPopupMenu(confirmCancelPopupMenu);
if (nextState != REVERSE_CONFIRM)
selectEdge = null;
updateDiagram();
confirmCancelPopupMenu.show(this, lastClickedPoint.x+20,
lastClickedPoint.y+20);
}
void unlinkKnotNextState(int nextState) {
statusLabel.setText("confirm or cancel");
state = nextState;
setPopupMenu(confirmCancelPopupMenu);
selectEdge = null;
updateDiagram();
confirmCancelPopupMenu.show(this, lastClickedPoint.x + 20,
lastClickedPoint.y + 20);
}
Point gridCorrect(Point p) {
if (!gridOn) return p;
int x = p.x, y = p.y;
x = ((x + GRID_DELTA/2)/GRID_DELTA) * GRID_DELTA;
y = ((y + GRID_DELTA/2)/GRID_DELTA) * GRID_DELTA;
return new Point(x, y);
}
public void mouseClicked(MouseEvent me) {
Pt newPt = null, lastPt = null;
Edge newEdge = null;
Point p = me.getPoint();
Point correctedPoint = gridCorrect(p);
Edge clickedEdge = null;
int nextState = 0;
lastClickedPoint = p;
System.out.println("in mouseClicked last clicked point = " + p.x + "," + p.y);
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
if (state == RECT_UNKNOT) return;
String r3Error = "";
if (p.y < FORBIDDEN_Y) return;
switch (state) {
case BETWEEN_KNOTS:
newPt = new NXPt(correctedPoint.x, correctedPoint.y, null, 0);
if (Geom.nearerThan(newPt, chosenPoints, nChosenPoints, tolerance)) {
statusLabel.setText("too near existing points");
break;
}
startPt = (NXPt) newPt; // for use in close
state = VERTEX;
statusLabel.setText("expecting vertex");
lastPtLoc = chosenPoints[nChosenPoints++] = correctedPoint;
setPopupMenu(vertexPopupMenu);
knotId = link.newKnot();
System.out.println("calling addVertex for BETWEEN_KNOTS");
addVertex(p);
updateInfoAndDiagram();
break;
case VERTEX:
lastPt = newPt;
newPt = new NXPt(correctedPoint.x, correctedPoint.y, null, 0);
newEdge = new Edge(lastPt, newPt, null, 0);
if (!addNewEdge(newEdge, pts, edges, tolerance)) {
statusLabel.setText("too crowded");
return;
}
statusLabel.setText("expecting vertex");
if (nChosenPoints < chosenPoints.length) {
lastPtLoc = chosenPoints[nChosenPoints++] =
gridOn ? correctedPoint : correctPoint(p, lastPtLoc);
updateDiagram();
}
else {
statusLabel.setText("too many points – ignored");
return;
}
break;
case CROSSING:
toggleCrossing(p);
if (altFlag) setAlt(p);
updateDiagram();
break;
/*
case JOIN_VERTICAL: case JOIN_HORIZONTAL:
joinHorV(p);
setState(COMPLETE, completePopupMenu); // will do updateDiagram
break;
case NULLIFY:
nullify(p);
setState(COMPLETE, completePopupMenu); // will do updateDiagram
break;
case EXPAND_CROSSING:
expandCrossing(p);
setState(EXPAND, expandPopupMenu); // will do updateDiagram
break;
*/
case R1I_CROSSING:
link.r1iToggleCrossing();
updateDiagram();
break;
case MAC_CROSSING:
link.macToggleCrossings();
updateDiagram();
break;
case R1I: case MAC:
clickedEdge = null;
if (pickMode == POINTS_MODE) {
if (nChosenPoints < chosenPoints.length) {
lastPtLoc = chosenPoints[nChosenPoints++] =
gridOn ? correctedPoint : correctPoint(p, lastPtLoc);
}
else {
statusLabel.setText("too many points – ignored");
return;
}
}
else if ( (clickedEdge = findEdge(p)) == null ) {
statusLabel.setText("click closer to edge");
return;
}
else {
System.out.println("#chosen edges = " + nChosenEdges);
System.out.println("last clicked edge = " + ((lastClickedEdge == null) ?
"null" : lastClickedEdge.toString())
+ " clicked edge = " + ((clickedEdge == null) ?
"null" : clickedEdge.toString()));
if (nChosenEdges == 0) {
lastClickedEdge = chosenEdge1 = clickedEdge;
nChosenEdges++;
System.out.println("#chosen edges = " + nChosenEdges);
System.out.println("last clicked edge = " + ((lastClickedEdge == null) ?
"null" : lastClickedEdge.toString())
+ " clicked edge = " + ((clickedEdge == null) ?
"null" : clickedEdge.toString()));
}
else if (lastClickedEdge.getKnotId() != clickedEdge.getKnotId()) {
lastClickedEdge = chosenEdge1 = clickedEdge;
nChosenEdges = 1;
}
else if (lastClickedEdge == clickedEdge) {
statusLabel.setText("choose a different edge");
return;
}
else if (nChosenEdges == 1) {
lastClickedEdge = chosenEdge2 = clickedEdge;
nChosenEdges++;
System.out.println("#chosen edges = " + nChosenEdges);
System.out.println("last clicked edge = " + ((lastClickedEdge == null) ?
"null" : lastClickedEdge.toString())
+ " clicked edge = " + ((clickedEdge == null) ?
"null" : clickedEdge.toString()));
}
else { // discard oldest edges if more than two chosen
chosenEdge1 = chosenEdge2;
lastClickedEdge = chosenEdge2 = clickedEdge;
}
}
updateInfoAndDiagram();
break;
case FIRST_EDGE: case MARK_KNOT: case REVERSE_KNOT:
Link cur = link;
selectEdge = findEdge(cur, p);
if (selectEdge == null) {
statusLabel.setText("click closer to edge");
return;
}
if (state == FIRST_EDGE)
cur.setFirstEdge(selectEdge.getKnotId(), selectEdge);
else if (state == REVERSE_KNOT)
link.reverseKnot(selectEdge.getKnotId());
else cur.markKnot(selectEdge.getKnotId());
updateDiagram();
break;
/*
case EXPAND:
Dimension size = getSize();
int px = p.x, py = p.y;
String nodesBar = root.nodesBar();
FontMetrics fm = getFontMetrics(getFont());
int nodesBarWd = fm.stringWidth(nodesBar);
if (NODES_BAR_X <= px && px < NODES_BAR_X + nodesBarWd
&& size.height - NODES_BAR_Y - fm.getAscent() <= py
&& py < size.height - NODES_BAR_Y + fm.getDescent()) {
int ii = 0;
while (NODES_BAR_X + fm.stringWidth(nodesBar.substring(0,ii+1))
< px) ii++;
while (nodesBar.charAt(ii) != ' ') ii--;
int j = nodesBar.indexOf(' ', ii+1);
int k = Integer.parseInt(nodesBar.substring(ii+1, j));
currentNode = root.node(k);
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
return;
}
// else handle like COMPLETE
*/
case COMPLETE:
selectEdge = findEdge(p);
Edge e = selectEdge;
if (selectEdge == null) return;
while (selectEdge.getInPt() instanceof NXPt) {
selectEdge = selectEdge.getPrev();
if (selectEdge == e) {
statusLabel.setText("no more crossings");
selectEdge = null;
return;
}
}
statusLabel.setText("arc chosen");
updateDiagram();
break;
case UNLINK_KNOT: case ROTATE: // case REVERSE_KNOT
case MULTI_KNT_UNLINK: // case MARK_KNOT
selectEdge = findEdge(p);
if (selectEdge == null) {
statusLabel.setText("click closer to edge");
return;
}
Link orig = new Link(link);
try {
switch (state) {
case UNLINK_KNOT:
link.unlinkKnot(selectEdge.getKnotId());
nextState = UNLINK_CONFIRM;
break;
case MULTI_KNT_UNLINK:
link.unlinkKnot(selectEdge.getKnotId());
nextState = MULTI_KNT_CONFIRM;
break;
case ROTATE:
link.rotate(selectEdge.getKnotId(), degCcw);
nextState = ROTATE_CONFIRM;
break;
}
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
return;
}
if (state != UNLINK_KNOT) tentativeAddHistory(orig, nextState);
else unlinkKnotNextState(nextState);
break;
default:
statusLabel.setText("mode " + modeNames[state] +
": unexpected mouse click");
}
}
public void mouseEntered(MouseEvent me) {
}
public void mouseExited(MouseEvent me) {
}
public void mouseMoved(MouseEvent me) {
}
public void drawRectUnknot() {
Rectangle[] updateClipRegions = new Rectangle[4];
Graphics g = getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawRect(rectLeft, rectTop, rectWidth, rectHeight);
}
public void mousePressed(MouseEvent me) {
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
Point p = me.getPoint();
int x = p.x, y = p.y;
Point correctedPoint = gridCorrect(p);
int cx = correctedPoint.x, cy = correctedPoint.y;
if (y < FORBIDDEN_Y) return;
switch (state) {
case BETWEEN_KNOTS: case EXPAND: case COMPLETE:
if (link == null) link = new Link();
rectLeft = cx; rectTop = cy;
return;
case RECT_UNKNOT: case CLIP_RECT: case DUP_KNOT_CHOOSE: case DUP_KNOT_MOVE:
break;
default:
return;
}
if (state == DUP_KNOT_CHOOSE) {
Edge clickedEdge = findEdge(p);
if (clickedEdge == null) {
statusLabel.setText("click closer to edge");
return;
}
lastDupPoint = correctedPoint;
nOldKnots = link.dupChosenKnot(clickedEdge);
state = DUP_KNOT_MOVE;
Graphics g = offscreen.getGraphics();
link.xorDraw(g, knotId, true);
updateDiagram();
return;
}
if (state == DUP_KNOT_MOVE && lastDupPoint == null) {
p = correctedPoint;
lastDupPoint = p;
return;
}
if (rectStage == PRESENT)
drawRectUnknot(); // clear old rect
rectLeft = cx; rectTop = cy; rectWidth = rectHeight = 1;
rectStage = PRESENT;
drawRectUnknot();
}
public void mouseDragged(MouseEvent me) {
System.out.println("in mouseDragged state = " + state);
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
Point p = me.getPoint();
int x = p.x, y = p.y;
Point correctedPoint = gridCorrect(p);
int cx = correctedPoint.x, cy = correctedPoint.y;
if (y < FORBIDDEN_Y) return;
switch (state) {
case BETWEEN_KNOTS: case EXPAND: case RECT_UNKNOT:
case CLIP_RECT: case DUP_KNOT_MOVE: case COMPLETE: case ITERATE:
break;
default:
return;
}
if (state == DUP_KNOT_MOVE) {
Graphics g = getGraphics();
Graphics og = offscreen.getGraphics();
link.xorDraw(og, nOldKnots, true);
link.moveKnots(nOldKnots, cx-lastDupPoint.x, cy-lastDupPoint.y);
link.xorDraw(og, nOldKnots, true);
lastDupPoint = correctedPoint;
g.drawImage(offscreen, 0, 0, this);
return;
}
// if (state == BETWEEN_KNOTS) {
// state = RECT_UNKNOT; setPopupMenu(confirmCancelPopupMenu);
// statusLabel.setText("rect unknot");
// rectStage = PRESENT;
// // state = RECT_UNKNOT; setPopupMenu(confirmCancelPopupMenu);
// // statusLabel.setText("rect unknot");
// // rectStage = PRESENT;
// }
if (state == BETWEEN_KNOTS) {
setPopupMenu(confirmCancelPopupMenu);
return;
}
else if (state == EXPAND) {
state = CLIP_RECT; setPopupMenu(confirmCancelPopupMenu);
statusLabel.setText("clip rect");
rectStage = PRESENT;
}
else if (state == COMPLETE) {
// state = ITERATE; setPopupMenu(confirmCancelPopupMenu);
// statusLabel.setText("iterate");
// rectStage = PRESENT;
}
else if ((state == RECT_UNKNOT || state == CLIP_RECT || state == ITERATE)
&& rectStage == PRESENT)
drawRectUnknot();
rectWidth = cx-rectLeft; rectHeight = cy-rectTop;
drawRectUnknot();
}
public void mouseReleased(MouseEvent me) {
// if (state == ZIGZAG) return;
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
if (state == DUP_KNOT_MOVE) {
completeDupKnot();
updateDiagram();
return;
}
Point p = me.getPoint();
int x = p.x, y = p.y;
Point correctedPoint = gridCorrect(p);
int cx = correctedPoint.x, cy = correctedPoint.y;
if (y < FORBIDDEN_Y || (state != RECT_UNKNOT && state != ITERATE
&& state != EXPAND && state != CLIP_RECT))
return;
if (state == ITERATE) {
// if (!fitForIterate()) {
// setState(COMPLETE, completePopupMenu);
// return;
// }
// try {
// if (currKntName == null) throw new Exception("no name for iterate");
// iterLink = new UnitLink(link);
// Iterate.checkFitness(iterLink, rectLeft, rectLeft + rectWidth,
// ITERATE_DX, ITERATE_GAP, currKntName);
// doIterate();
// return;
// } catch (Exception anyExc) {
// System.out.println(anyExc);
// statusLabel.setText(anyExc.getMessage());
// setState(COMPLETE, completePopupMenu);
return;
// }
}
// confirmCancelPopupMenu.show(this, x+5, y+5);
}
// boolean fitForIterate() {
// int rectRight = rectLeft+rectWidth-1;
// iterLink = new UnitLink(link);
// Vector v = iterLink.getUnfitPts(rectLeft, rectRight, ITERATE_DX);
// if (v.size() != 0) {
// statusLabel(“#unfit points = “ + v.size());
// return false;
// }
// return true;
//}
void drawCross(Graphics g, Color c, Point p) {
Color oldColor = g.getColor();
g.setColor( c );
g.drawLine(p.x-2, p.y, p.x+2, p.y);
g.drawLine(p.x, p.y-2, p.x, p.y+2);
g.setColor(oldColor);
}
void drawThinLine(Graphics g, Color c, Point p1, Point p2) {
Color oldColor = g.getColor();
g.setColor( c );
g.drawLine(p1.x, p1.y, p2.x, p2.y);
g.setColor(oldColor);
}
void drawGrid(Graphics g) {
if (!gridOn) return;
int x = 0, y = 0;
Color oldColor = g.getColor();
g.setColor(Color.cyan.brighter());
g.setXORMode(Color.white);
Dimension size = getSize();
while (x < size.width) {
if (x % (GRID_DELTA*10) != 0) g.drawLine(x, 0, x, size.height-1);
x += GRID_DELTA;
}
while (y < size.height) {
if (y % (GRID_DELTA*10) != 0) g.drawLine(0, y, size.width-1, y);
y += GRID_DELTA;
}
x = y = 0;
g.setColor(Color.cyan.darker());
while (x < size.width) {
g.drawLine(x, 0, x, size.height-1);
x += GRID_DELTA*10;
}
while (y < size.height) {
g.drawLine(0, y, size.width-1, y);
y += GRID_DELTA*10;
}
g.setColor(oldColor);
g.setPaintMode();
}
/*
public void drawBackground(Graphics g) {
if (background == null) return;
g.drawImage(background, 0, 0, this);
}
*/
public void paint(Graphics g) {
System.out.println("in paint state = " + state);
if (link == null) return;
// drawBackground(g);
drawGrid(g);
if (state == TRICOLOR) {
link.tricolorDraw(g);
return;
}
else if (state == SKELETON || state == SIMPLIFY) {
skeletonCopy.draw(g, false);
return;
}
if (state == DUP_KNOT_MOVE) {
g.drawImage(offscreen, 0, 0, this);
return;
}
// System.out.println("in paint, about to call link.draw link to draw:");
// link.print();
// System.out.println("end of link to draw");
link.draw(g, state == VERTEX // || state == BETWEEN_KNOTS
|| state == RECT_UNKNOT);
// in VERTEX or RECT_UNKNOT state, ignore crossings
/*
if (currentNode != null) {
Point[] clipRect = currentNode.clipRect;
if (clipRect != null && clipRect[0].x != 0) { // draw clip rect
Point lowerLeft = new Point(clipRect[0].x, clipRect[1].y);
Point upperRight = new Point(clipRect[1].x, clipRect[0].y);
drawThinLine(g, Color.black, clipRect[0], lowerLeft);
drawThinLine(g, Color.black, clipRect[0], upperRight);
drawThinLine(g, Color.black, clipRect[1], lowerLeft);
drawThinLine(g, Color.black, clipRect[1], upperRight);
}
Dimension size = getSize();
String nodesBar = root.nodesBar();
g.drawString(nodesBar, NODES_BAR_X, pageHeight - NODES_BAR_Y);
FontMetrics fm = getFontMetrics(getFont());
String currentSeqNo = currentNode.seqNo + " ";
int offset = nodesBar.indexOf(currentSeqNo);
g.drawString("^", NODES_BAR_X +
fm.stringWidth(nodesBar.substring(0, offset)),
size.height - NODES_BAR_Y + fm.getHeight());
}
*/
// if (state == JOIN_VERTICAL || state == JOIN_HORIZONTAL ||
// state == NULLIFY || state == EXPAND_CROSSING) {
// link.hiliteCrossings(g, radius);
// }
if (state == CROSSING) {
Color oldColor = g.getColor();
g.setColor(Color.blue);
for (int ii = 0; ii < intersectCt; ii++)
g.drawOval(xptx[ii]-radius, xpty[ii]-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
if ((state == COMPLETE || state == EXPAND) && selectEdge != null) {
Edge e = selectEdge;
e.draw(g, Color.blue, false, link.marked[e.getKnotId()]);
while (e.getOutPt() instanceof NXPt) {
e.getNext();
e.draw(g, Color.blue, false, !link.marked[e.getKnotId()]);
}
}
if ((state == STRAIGHTEN || state == R1I || state == MAC || state == R2I)
&& nChosenEdges != 0) {
chosenEdge1.draw(g, Color.blue, false,
!link.marked[chosenEdge1.getKnotId()]);
if (nChosenEdges > 1) {
Edge e = chosenEdge1;
do {
e = e.getNext();
e.draw(g, Color.blue, false, link.marked[e.getKnotId()]);
} while (e != chosenEdge2);
}
Point p = chosenEdge1.getInPt().getLocation();
Color oldColor = g.getColor();
g.setColor(Color.blue);
g.fillOval(p.x-radius, p.y-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
if ((state == R1I || state == MAC || state == VERTEX)
&& nChosenPoints != 0) {
for (int ii = 0; ii < nChosenPoints; ii++)
drawCross(g, Color.magenta, chosenPoints[ii]);
if (nChosenEdges > 0) drawThinLine(g, Color.magenta,
chosenEdge1.getInPt().getLocation(), chosenPoints[0]);
for (int ii = 0; ii < nChosenPoints-1; ii++)
drawThinLine(g, Color.magenta, chosenPoints[ii], chosenPoints[ii+1]);
}
if (state == R1I_CROSSING) {
Point p = link.getR1iXPtLoc();
Color oldColor = g.getColor();
g.setColor(Color.blue);
g.drawOval(p.x-radius, p.y-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
else if (state == MAC_CROSSING) {
Point[] pa = link.getMacXPtLocArray();
Color oldColor = g.getColor();
g.setColor(Color.blue);
for (int ii = 0; ii < pa.length; ii++)
g.drawOval(pa[ii].x-radius, pa[ii].y-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
if ((state == RECT_UNKNOT || state == CLIP_RECT || state == ITERATE)
&& rectStage == PRESENT) drawRectUnknot();
}
void updateInfoAndDiagram() {
if (reviewMode) report(seriesName[currentSeries]);
else report(currKntName);
updateDiagram();
}
void updateDiagram() {
System.out.println("in updateDiagram state = " + state);
// update(getGraphics());
if (initializing) {
initializing = false;
update(getGraphics());
// initPopupMenu.show(this, 200, 200);
return;
}
Graphics g = getGraphics();
makeOffscreen();
Graphics og = offscreen.getGraphics();
update(og);
g.drawImage(offscreen, 0, 0, null);
// validate();
}
public void takeThis(Link link) {
this.link = link;
updateDiagram();
}
}
LinkFrame.java:
---------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkFrame extends Frame
implements ActionListener {
Button initButton, confirmButton, closeButton, completeButton;
Button cancelButton;
Button r1dButton, r2dButton, r3Button, straightenButton;
Button macButton, edgesButton, pointsButton, flipButton;
Button r1iButton, r2iButton;
Label statusLabel;
Panel controlPanel, centerPanel;
LinkCanvas lc;
public LinkFrame(String[] args) {
statusLabel = new Label("this area for status and error messages");
centerPanel = new Panel();
centerPanel.setLayout(new BorderLayout());
centerPanel.add("North", statusLabel);
lc = new LinkCanvas(this, new Dimension(600, 500), statusLabel,
new Label(" "));
// status label
centerPanel.add("Center", lc);
add("Center", centerPanel);
pack();
setVisible(true);
try {
Thread.sleep(500);
}
catch (Exception anyExc) {
}
if (args.length != 0) {
String name = args[0];
if (!name.endsWith(".knt")) name += ".knt";
lc.load(name);
}
// lc.showInitPopupMenu();
}
public void setArcRadius(int r) {
lc.setArcRadius(r);
}
public void actionPerformed(ActionEvent e) {
}
public void takeThis(Link link) {
lc.takeThis(link);
}
public static void main(String[] args) {
LinkFrame f = new LinkFrame(args);
// if (args.length > 0) f.setArcRadius(Integer.parseInt(args[0]));
try {
Thread.sleep(100000);
}
catch (Exception anyExc) { }
}
}
LinkReader.java:
----------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkReader {
BufferedReader br;
Link link;
String s = "";
int pos = 0, slen = 0;
Hashtable ht;
public LinkReader(BufferedReader br) {
this.br = br;
}
public int getNLinks() {
try {
return Integer.parseInt(br.readLine());
}
catch (Exception anyExc) {
return 0;
}
}
void getLine() {
try {
s = br.readLine();
}
catch (Exception anyExc) {
s = "";
}
slen = s.length();
pos = 0;
// System.out.println("line from knt file = " + s);
}
int getInt() {
int pos1 = (s + " ").indexOf(' ', pos);
int res = Integer.parseInt(s.substring(pos, pos1));
pos = pos1+1;
return res;
}
String getCode() {
if (pos >= slen) getLine();
int pos1 = s.indexOf('#', pos);
String res = s.substring(pos, pos1+1);
pos = pos1+1;
return res;
}
String getString() {
if (pos > s.length()) return "";
return s.substring(pos);
}
int getSelectedEdgeCode() {
// 0 = not selected 1 = first selected edge 2 = last selected edge
if (pos >= slen) return 0;
char c = s.charAt(pos++);
if (c == 'f') return 1;
else if (c == 'l') return 2;
pos--; return 0;
}
int getFirstEdgeCode() {
// 0 = not first 1 = first
if (pos >= slen) return 0;
char c = s.charAt(pos++);
if (c == 'F') return 1;
pos--; return 0;
}
Pt getPt(int knotId) {
XOPt xOPt = null;
String hashKey = "";
Pt p = null, res = null;
String code = getCode();
// System.out.println("Pt code = " + code);
char type = code.charAt(0);
if (type == 't') {
System.out.println("null Pt");
return (Pt) null;
}
// System.out.print("edge code = " + code.charAt(0));
int comma = code.indexOf(',');
int x = Integer.parseInt(code.substring(1, comma));
// System.out.println(" x = " + x);
// System.out.print("remaining line = " + code.substring(comma+1));
int hashSign = code.indexOf('#', comma+1);
int comma1 = code.indexOf(',', comma+1);
int yEnd = comma1;
if (yEnd < 0) yEnd = hashSign;
else yEnd = Math.min(hashSign, comma1);
// System.out.print(" hashSign at " + hashSign + " second comma at " + comma1
// + " yEnd at " + yEnd);
int y = Integer.parseInt(code.substring(comma+1, yEnd));
// System.out.print(" y = " + y + " ");
int otherKnotId = 0;
if (comma1 > 0)
otherKnotId = Integer.parseInt(code.substring(comma1+1, hashSign));
switch (code.charAt(0)) {
case 'n':
res = new NXPt(x, y, link, knotId);
System.out.println("Pt is " + res.encoding());
return res;
case 'o':
hashKey = "x" + x + "," + y;
p = (Pt) ht.get(hashKey);
if (p != null) {
p.setKnotId(knotId);
System.out.println("Pt is " + p.encoding());
return p;
}
xOPt = new XOPt(x, y, link, knotId, otherKnotId);
ht.put(hashKey, xOPt.getMate());
// System.out.println("Pt is " + xOPt.encoding());
return xOPt;
case 'u':
hashKey = "x" + x + "," + y;
p = (Pt) ht.get(hashKey);
if (p != null) {
p.setKnotId(knotId);
// System.out.println("Pt is " + p.encoding());
return p;
}
xOPt = new XOPt(x, y, link, otherKnotId, knotId);
ht.put(hashKey, xOPt);
// System.out.println("Pt is " + xOPt.getMate().encoding());
return xOPt.getMate();
}
System.out.println("Pt is null");
return (Pt) null;
}
void setSelectedEdge(Link link, Edge e, int selectedEdgeCode) {
switch (selectedEdgeCode) {
case 0:
return;
case 1:
link.firstSelectedEdge = e;
return;
case 2:
link.lastSelectedEdge = e;
return;
}
}
public Link loadLink() {
link = new Link();
ht = new Hashtable();
Pt currentPt = null;
getLine();
link.nKnots = getInt();
link.totalEdges = getInt();
System.out.println("in loadLink: current link #knots = " + link.nKnots +
" #edges = " + link.totalEdges);
getLine();
// System.out.println("nos. of XPts in the knots:");
for (int knotId = 0; knotId < link.nKnots; knotId++) {
int tempNXPt = link.nXPt[knotId] = getInt();
// System.out.print(tempNXPt + " ");
if (tempNXPt < 0) {
link.nXPt[knotId] = (-tempNXPt)/10;
link.marked[knotId] = true;
}
// System.out.println();
}
int selectedEdgeCode = 0, firstEdgeCode = 0;
for (int knotId = 0; knotId < link.nKnots; knotId++) {
// System.out.println("reading knot#" + knotId);
getLine(); // read the line containing #edges in knot
link.nKnotEdges[knotId] = getInt();
// System.out.println("#edges in knot#" + knotId + " = " + link.nKnotEdges[knotId]);
getLine();
Pt startPt = getPt(knotId);
// System.out.println("startPt = " + startPt.encoding());
firstEdgeCode = getFirstEdgeCode();
selectedEdgeCode = getSelectedEdgeCode();
Pt lastPt = getPt(knotId);
Edge startEdge = new Edge(startPt, lastPt, link, knotId);
// System.out.println("startEdge = " + startEdge.toString());
setSelectedEdge(link, startEdge, selectedEdgeCode);
Edge lastEdge = startEdge, currentEdge;
link.firstEdge[knotId] = startEdge;
startPt.setOutEdge(startEdge);
lastPt.setInEdge(startEdge);
for (int i = 2; i < link.nKnotEdges[knotId]; i++ ) {
// while ( (currentPt = getPt(knotId)) != null ) {
// System.out.println("i = " + i + " ");
currentPt = getPt(knotId);
currentEdge = new Edge(lastPt, currentPt, link, knotId);
// System.out.println(currentEdge.toString() + " firstEdgeCode = " + firstEdgeCode);
if (firstEdgeCode > 0) link.firstEdge[knotId] = currentEdge;
setSelectedEdge(link, currentEdge, selectedEdgeCode);
firstEdgeCode = getFirstEdgeCode();
selectedEdgeCode = getSelectedEdgeCode();
lastEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
lastPt.setOutEdge(currentEdge);
currentPt.setInEdge(currentEdge);
lastEdge = currentEdge; lastPt = currentPt;
}
// at this point, we have read all the edges in the knot
currentEdge = new Edge(lastPt, startPt, link, knotId);
if (firstEdgeCode > 0) link.firstEdge[knotId] = currentEdge;
setSelectedEdge(link, currentEdge, selectedEdgeCode);
lastEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
lastPt.setOutEdge(currentEdge);
startPt.setInEdge(currentEdge);
currentEdge.setNext(startEdge);
startEdge.setPrev(currentEdge);
// System.out.println("last edge = " + currentEdge.toString());
}
System.out.println("about to call link.linkXPts");
link.linkXPts();
System.out.println("about to call link.computeTotalCrossings");
link.computeTotalCrossings();
System.out.println("about to return from loadLink");
return link;
}
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("filename expected");
System.exit(0);
}
Link x = null;
try {
BufferedReader br = new BufferedReader(new FileReader(args[0]));
LinkReader lr = new LinkReader(br);
System.out.println("#links in series = " +
Integer.parseInt(br.readLine()));
x = lr.loadLink();
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
System.out.println("finished reading");
x.print();
LinkFrame f = new LinkFrame((String[]) null);
f.takeThis(x);
try {
Thread.sleep(100000);
}
catch (Exception anyExc) { }
}
}
LinkWriter.java:
----------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkWriter {
BufferedWriter bw, aw;
static String wrapPath = "currentpoint stroke newpath moveto";
int radius = 3;
int heightUsed = 0, widthUsed = 0, bandHt = 0;
static final int MAX_HEIGHT = 750;
static final int MAX_WIDTH = 600;
static final int VERTICAL_GAP = 40;
static final int HORIZONTAL_GAP = 40;
static final int DX = 0;
static final int DY = 10;
static final int ADJUST = 10;
static final int CIRCLE_RADIUS = 3;
static final int ARROW_DX = 3;
int maxHeight = MAX_HEIGHT;
int maxWidth = MAX_WIDTH;
double scaleFactor = 1.0;
int pageNum = 0;
public static final int ACTUAL_PAGE_HEIGHT = 790;
static final int COLOR = 0;
static final int GREYSCALE = 1;
static final int BLACK = 2;
public LinkWriter(BufferedWriter bw) {
this.bw = bw;
}
public void setPSPageSize(int w, int h) {
maxWidth = w;
maxHeight = h;
}
public void setAuxWriter(BufferedWriter aw) {
this.aw = aw;
}
public void write(String s) {
try {
System.out.println("in write(String) s = " + s);
bw.write(s, 0, s.length());
} catch (Exception anyExc) {
System.out.println(anyExc);
}
}
public void writeLine(String s) {
try {
bw.write(s, 0, s.length());
bw.newLine();
} catch (Exception anyExc) {
}
}
public void writeLine() {
try {
bw.newLine();
} catch (Exception anyExc) {
}
}
public void awWriteLine(String s) {
try {
aw.write(s, 0, s.length());
aw.newLine();
} catch (Exception anyExc) {
}
}
public void saveNLinks(int n) {
writeLine("" + n);
}
void selectedEdgeCode(Pt p, Edge e1, Edge e2) {
Edge e = p.getOutEdge();
if (e == e1) write(" ");
else if (e == e2) write(" ");
}
void firstEdgeCode(Pt p, Edge firstEdge) {
Edge e = p.getOutEdge();
if (e == firstEdge) write("F");
}
public void saveLink(Link link) throws Exception {
System.out.println(link.nKnots + " " + link.totalEdges);
writeLine(link.nKnots + " " + link.totalEdges);
for (int knotId = 0; knotId < link.nKnots; knotId++) {
write("" + link.nXPt[knotId] + " ");
}
writeLine();
for (int knotId = 0; knotId < link.nKnots; knotId++) {
System.out.println("#edges in knot#" + knotId + " = " + link.nKnotEdges[knotId]);
writeLine("" + link.nKnotEdges[knotId]);
System.out.println("knotId = " + knotId);
Edge firstEdge = link.getFirstEdge(knotId);
Pt startPt = firstEdge.getInPt();
while (startPt instanceof XPt)
startPt = startPt.getOutEdge().getOutPt();
System.out.println("found startPt " + startPt.encoding());
Pt pt = startPt;
int ct = 0;
// do {
// System.out.println("ct = " + ct + " pt = " + pt.encoding());
// write(pt.encoding());
// System.out.println("calling firstEdgeCode");
// firstEdgeCode(pt, firstEdge);
// System.out.println("calling selectedEdgeCode");
// selectedEdgeCode(pt, link.firstSelectedEdge,
// link.lastSelectedEdge);
// ct++;
// if (ct % 5 == 0) writeLine();
// bw.flush();
// pt = pt.getOutEdge().getOutPt();
// System.out.println("new pt = " + pt.encoding());
// System.out.println("at loop test pt = " + pt.encoding() + " startPt = "
// + startPt.encoding());
// if (pt == startPt) break;
// } while (true);
for (int i = 0; i < link.nKnotEdges[knotId]; i++) {
System.out.println("ct = " + ct + " pt = " + pt.encoding());
write(pt.encoding());
System.out.println("calling firstEdgeCode");
firstEdgeCode(pt, firstEdge);
System.out.println("calling selectedEdgeCode");
selectedEdgeCode(pt, link.firstSelectedEdge, link.lastSelectedEdge);
ct++;
if (ct % 5 == 0) writeLine();
// bw.flush();
pt = pt.getOutEdge().getOutPt();
System.out.println("new pt = " + pt.encoding());
System.out.println("at loop test pt = " + pt.encoding() + " startPt = "
+ startPt.encoding());
}
System.out.println("after inner loop");
// writeLine("t#");
writeLine();
}
System.out.println("after outer loop");
}
public void saveKnot(Link link, int knotId, int shiftX) {
Edge firstEdge = link.getFirstEdge(knotId);
Pt startPt = firstEdge.getInPt();
while (startPt instanceof XPt)
startPt = startPt.getOutEdge().getOutPt();
Pt pt = startPt;
int ct = 0;
do {
// write(pt.encoding(shiftX));
write(pt.encoding());
ct++;
if (ct % 5 == 0) writeLine();
pt = pt.getOutEdge().getOutPt();
} while (pt != startPt);
writeLine("t#");
}
public void saveSegment(BdyPt startPt, int shiftX, int lastKinkMidX,
int iterate_gap) {
Pt pt = startPt;
int ct = 0;
int lastKinkLeftX = lastKinkMidX - iterate_gap;
do {
int x = pt.x + iterate_gap;
// worry about removing the last kink due to alignment
ct++;
if (lastKinkMidX < 0 || x < lastKinkLeftX)
// write(pt.encoding(shiftX));
write(pt.encoding());
else if (x <= lastKinkMidX) ;
// else write(pt.encoding(shiftX - 2 * iterate_gap));
else write(pt.encoding());
if (ct % 5 == 0) writeLine();
pt = pt.getOutEdge().getOutPt();
} while (!(pt instanceof BdyPt));
if (ct % 5 > 0) writeLine();
}
String lineto(String postscriptCode) {
// return just the lineto part of the code for an edge
int p = postscriptCode.indexOf("moveto");
return postscriptCode.substring(p + 6);
}
public void savePS(Link link, int boxWd, int boxHt, int colorType) {
String[] knotColorStrings = null;
if (colorType == COLOR) knotColorStrings = Link.getKnotColorStrings();
else if (colorType == GREYSCALE) knotColorStrings = Link.getKnotBWStrings();
else {
knotColorStrings = new String[1];
knotColorStrings[0] = Link.getSelectedEdgeColorString();
}
String selectedEdgeColorString = "1 setlinewidth";
Edge firstSelectedEdge = link.firstSelectedEdge;
Edge lastSelectedEdge = link.lastSelectedEdge;
int[] minMaxXY = link.getMinMaxXY();
int minX = minMaxXY[0], maxX = minMaxXY[1],
minY = minMaxXY[2], maxY = minMaxXY[3];
double r1 = ((double) boxWd / (maxX - minX));
double r2 = ((double) boxHt / (maxY - minY));
double r = (r1 < r2) ? r1 : r2;
for (int knotId = 0; knotId < link.nKnots; knotId++) {
writeLine(knotColorStrings[knotId % knotColorStrings.length]);
writeLine("newpath");
int nXPt = link.getNXPt(knotId);
XUPt xUPt = null;
if (nXPt > 0) {
XPt xPt = link.getFirstXPt(knotId);
for (int ii = 0; ii < nXPt; ii++) {
if (xPt instanceof XUPt) {
xUPt = (XUPt) xPt;
break;
}
xPt = xPt.getNext();
}
}
if (xUPt == null) {
boolean twoParts = false;
Edge startEdge = link.getFirstEdge(knotId);
Edge e = startEdge;
if (firstSelectedEdge != null &&
firstSelectedEdge.getKnotId() == knotId) {
startEdge = e = firstSelectedEdge;
twoParts = true;
writeLine(selectedEdgeColorString);
}
writeLine(e.postscriptCode(minX, minY, r, boxHt));
if (e == lastSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
Edge endEdge = startEdge.getPrev();
while ((e = e.getNext()) != endEdge) {
if (e == firstSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
if (e == lastSelectedEdge)
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
}
if (twoParts)
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
else writeLine("closepath");
} else {
Edge e = xUPt.getOutEdge();
Edge startEdge = e;
if (firstSelectedEdge != null && firstSelectedEdge.getKnotId() == knotId) {
e = firstSelectedEdge;
while (!(e.getInPt() instanceof XUPt)) {
e = e.getPrev();
if (e == lastSelectedEdge) writeLine(selectedEdgeColorString);
}
startEdge = e;
}
do {
if (e == firstSelectedEdge)
writeLine(((e == startEdge) ? "" : wrapPath) +
selectedEdgeColorString);
writeLine(e.postscriptCode(minX, minY, r, boxHt));
if (e == lastSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
while (!(e.getOutPt() instanceof XUPt)) {
e = e.getNext();
if (e == firstSelectedEdge)
writeLine(wrapPath + selectedEdgeColorString);
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
if (e == lastSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
}
e = e.getNext();
} while (e != startEdge);
}
writeLine("stroke");
writeLine();
}
writeLine();
}
String midpoint(Point[] pa) {
return "" + pa[0].x + " " + pa[1].x + " add 2 div "
+ pa[0].y + " " + pa[1].y + " add 2 div ";
}
String begpoint(Point[] pa) {
return "" + pa[0].x + " " + pa[0].y + " ";
}
String endpoint(Point[] pa) {
return "" + pa[1].x + " " + pa[1].y + " ";
}
void arcto(Point[] pa) {
writeLine("" + pa[0].x + " " + pa[0].y + " "
+ pa[1].x + " " + pa[1].y + " " + radius + " arcto");
}
public void saveRoundPS(Link link, int boxWd, int boxHt, int radius, int colorType) {
this.radius = radius;
int[] minMaxXY = link.getMinMaxXY();
int minX = minMaxXY[0], minY = minMaxXY[1],
maxX = minMaxXY[2], maxY = minMaxXY[3];
double r1 = ((double) boxWd / (maxX - minX));
double r2 = ((double) boxHt / (maxY - minY));
double r = 1.0;
String[] knotColorStrings = null;
if (colorType == COLOR) knotColorStrings = Link.getKnotColorStrings();
else if (colorType == GREYSCALE) knotColorStrings = Link.getKnotBWStrings();
else {
knotColorStrings = new String[1];
knotColorStrings[0] = Link.getSelectedEdgeColorString();
}
Edge startEdge, e;
Point[] pa;
for (int knotId = 0; knotId < link.nKnots; knotId++) {
writeLine(knotColorStrings[knotId % knotColorStrings.length]);
XUPt xUPt = link.getFirstXUPt(knotId);
if (xUPt == null) { // no break
e = startEdge = link.getFirstEdge(knotId);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " moveto");
do {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
} while (e != startEdge);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " lineto");
writeLine("stroke");
} else { // broken by XUPt’s
XUPt p = xUPt;
do {
e = startEdge = p.getOutEdge();
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(begpoint(pa) + " moveto");
while (!(e.getOutPt() instanceof XUPt)) {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
}
writeLine(endpoint(pa) + " lineto");
writeLine("stroke");
p = (XUPt) e.getOutPt();
} while (p != xUPt);
}
writeLine();
}
writeLine();
}
public void saveRoundPS(Link link, int boxWd, int boxHt, int colorType) {
saveRoundPS(link, boxWd, boxHt, radius, colorType);
}
public void newPage() {
heightUsed = VERTICAL_GAP;
widthUsed = HORIZONTAL_GAP / 2;
bandHt = 0;
pageNum = 1;
}
public void wrapUp() {
awWriteLine("" + ((int) (heightUsed * scaleFactor)));
writeLine("stroke");
writeLine("flush");
writeLine("showpage");
writeLine("%]");
}
void displayHeading(String s) {
int len = s.length();
int segBeg = 0, segEnd;
char c = ' ', c1 = ' ';
do {
segEnd = segBeg;
while (segEnd < len) {
c = s.charAt(segEnd);
if (c == '^' || c == '_' || c == '|') break; // | = distant union
segEnd++;
}
if (segEnd > segBeg) {
writeLine("(" + s.substring(segBeg, segEnd) + ") show");
}
if (segEnd >= len) break;
segBeg = ++segEnd;
if (c == '|') writeLine("sqcup");
else { // ^ or _
String op = (c == '^') ? "showsupscr" : "showsubscr";
c1 = (segBeg < len) ? s.charAt(segBeg++) : ' ';
if (c1 != '{') {
writeLine("(" + c1 + ")" + op);
} else {
segEnd = segBeg;
while (segEnd < len && s.charAt(segEnd) != '}')
segEnd++;
writeLine("(" + s.substring(segBeg, segEnd) + ")" + op);
segBeg = segEnd + 1;
}
}
} while (segBeg < len);
}
void drawArrow(Edge e, int minX, int minY, double r, int boxHt) {
double angle = -e.getTrueAngle();
Point[] pa = e.PSEndpoints(minX, minY, r, boxHt);
int x = 0, y = 0;
int dx = pa[1].x - pa[0].x;
int dy = pa[1].y - pa[0].y;
double len = Math.sqrt(dx * dx + dy * dy);
if (len > 5 * ARROW_DX) {
x = (2 * pa[0].x + 3 * pa[1].x) / 5;
y = (2 * pa[0].y + 3 * pa[1].y) / 5;
} else {
x = (pa[0].x + 3 * pa[1].x) / 4;
y = (pa[0].y + 3 * pa[1].y) / 4;
}
writeLine(x + " " + y + " " + ARROW_DX + " " + angle + " arrow");
writeLine("stroke");
}
public void saveTreePSInit(double scaleFactor) {
int normalFontSize = (int) (12 * 0.7 / scaleFactor);
int subscrFontSize = (int) (8 * 0.7 / scaleFactor);
writeLine("/Math findfont fsz scalefont");
writeLine("/normalfont exch def");
writeLine("/sfsz " + subscrFontSize + " def");
writeLine("/Math findfont sfsz scalefont");
writeLine("/subscrfont exch def");
writeLine("");
writeLine("/showsubscr");
writeLine("{");
writeLine(" 0 sfsz 2 div rmoteto");
writeLine(" subscrfont setfont");
writeLine(" show");
writeLine(" normalfont setfont");
writeLine(" 0 sfsz 2 div rmoteto");
writeLine("} def");
writeLine("");
writeLine("/showsupscr");
writeLine("{");
writeLine(" 0 sfsz 2 div rmoveto");
writeLine(" subscrfont setfont");
writeLine(" show");
writeLine(" normalfont setfont");
writeLine(" 0 sfsz 2 div neg rmoveto");
writeLine("} def");
writeLine("");
writeLine("/sqcup");
writeLine("{");
writeLine(" currentlinewidth");
writeLine(" 1 setlinewidth");
writeLine(" fsz 4 div 0 rmoveto");
writeLine(" currentpoint");
writeLine(" 0 fsz 2 div rlineto");
writeLine(" moveto");
writeLine(" fsz 2 div 0 rlineto");
writeLine(" currentpoint");
writeLine(" 0 fsz 2 div rlineto");
writeLine(" moveto");
writeLine(" fsz 4 div 0 rmoveto");
writeLine(" setlinewidth");
writeLine(" def");
writeLine("");
writeLine("/arrow % x y dx angle");
writeLine("{");
writeLine(" aangle exch def");
writeLine(" adx exch def");
writeLine(" gsave");
writeLine(" translate");
writeLine(" aangle rotate");
writeLine(" 0 0 moveto");
writeLine(" adx neg adx neg rlineto");
writeLine(" 0 0 moveto");
writeLine(" adx neg adx rlineto");
writeLine(" stroke");
writeLine(" grestore");
writeLine("} def");
writeLine("%[ 0 " + (ACTUAL_PAGE_HEIGHT - maxHeight)
+ " " + maxWidth + " " + ACTUAL_PAGE_HEIGHT
);
writeLine("%%Page: 1 1");
writeLine("0 " + (ACTUAL_PAGE_HEIGHT - maxHeight) + " translate");
writeLine(scaleFactor + " " + scaleFactor + " scale");
newPage();
}
public void saveTreePS(Link link, Point expandedCrossing,
Point[] clipRect, String heading,
double scaleFactor, boolean showOrientations) {
this.scaleFactor = scaleFactor;
int scaledHeight = (int) (maxHeight / scaleFactor);
int scaledWidth = (int) (maxWidth / scaleFactor);
this.radius = radius;
int[] minMaxXY = link.getMinMaxXY();
int minX = minMaxXY[0], minY = minMaxXY[1],
maxX = minMaxXY[2], maxY = minMaxXY[3];
int boxHt = maxY - minY;
int boxWd = maxX - minX;
int left = 0, right = 0, top = 0, bottom = 0;
if (clipRect != null) {
left = clipRect[0].x;
top = clipRect[0].y;
right = clipRect[1].x;
bottom = clipRect[1].y;
}
if (left < minX) left = minX - ADJUST;
if (right == 0 || right > maxX) right = maxX + ADJUST;
if (top < minY) top = minY - ADJUST;
if (bottom == 0 || bottom > maxY) bottom = maxY - ADJUST;
int clipHt = bottom - top;
int actualHt = (clipHt == 0) ? boxHt : clipHt;
int clipWd = right - left;
int actualWd = (clipWd == 0) ? boxWd : clipWd;
boolean newBand = false;
if (widthUsed + HORIZONTAL_GAP + actualWd > scaledWidth)
newBand = true;
else if (heightUsed + actualHt - bandHt > scaledWidth)
newBand = true;
if (newBand) {
widthUsed = HORIZONTAL_GAP / 2;
if (actualHt + VERTICAL_GAP + heightUsed > scaledHeight) {
// heightUsed = -VERTICAL_GAP/2;
awWriteLine("" + ((int) (heightUsed * scaleFactor)));
heightUsed = 0;
writeLine("stroke");
writeLine("flush");
writeLine("showpage");
pageNum++;
writeLine("%%Page: " + pageNum + " " + pageNum);
writeLine("0 " + (ACTUAL_PAGE_HEIGHT - maxHeight)
+ " translate");
writeLine(scaleFactor + " " + scaleFactor + " scale");
}
bandHt = actualHt;
heightUsed += actualHt + VERTICAL_GAP;
writeLine("gsave");
writeLine((widthUsed + HORIZONTAL_GAP + " "
+ (scaledHeight - heightUsed)) + " translate");
widthUsed += HORIZONTAL_GAP + actualWd;
} else { // continue on same band
if (actualHt > bandHt) {
heightUsed += (actualHt - bandHt);
bandHt = actualHt;
}
writeLine("gsave");
writeLine((widthUsed + HORIZONTAL_GAP) + " "
+ (scaledHeight - heightUsed) + " translate");
widthUsed += HORIZONTAL_GAP + actualWd;
}
writeLine(DX + " " + (bandHt + DY) + " moveto");
displayHeading(heading);
writeLine("stroke");
writeLine("0 0 moveto");
if (clipHt > 0) { // take account of clip rect
writeLine((left - minX) + " neg" + (maxY - bottom) +
" neg translate");
writeLine("newpath");
writeLine("" + (left - minX) + " " + (maxY - bottom) + " moveto");
writeLine("0 " + (bottom - top) + " rlineto");
writeLine((right - left) + " 0 rlineto");
writeLine("0 " + (bottom - top) + " neg rlineto");
writeLine("closepath");
writeLine("clip");
}
writeLine("newpath");
double r = 1.0;
Edge startEdge, e;
Point[] pa;
clipRect[0] = new Point(left, top);
clipRect[1] = new Point(right, bottom);
for (int knotId = 0; knotId < link.nKnots; knotId++) {
if (link.knotOutsideClipRect(knotId, clipRect)) continue;
if (link.marked[knotId]) writeLine("2 setlinewidth");
XUPt xUPt = link.getFirstXUPt(knotId);
if (xUPt == null) { // no break
e = startEdge = link.getFirstEdge(knotId);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " moveto");
do {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
} while (e != startEdge);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " lineto");
writeLine("stroke");
} else { // broken by XUPt’s
XUPt p = xUPt;
do {
e = startEdge = p.getOutEdge();
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(begpoint(pa) + " moveto");
while (!(e.getOutPt() instanceof XUPt)) {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
}
writeLine(endpoint(pa) + " lineto");
writeLine("stroke");
p = (XUPt) e.getOutPt();
} while (p != xUPt);
}
if (showOrientations)
drawArrow(link.getFirstEdge(knotId), minX, minY, r, boxHt);
if (link.marked[knotId]) writeLine("1 setlinewidth");
writeLine();
}
if (expandedCrossing != null) {
XOPt xOPt = link.findXOPt(expandedCrossing);
Point xp = xOPt.getLocation();
writeLine((xp.x - minX) + " " + (boxHt - (xp.y - minY))
+ " " + CIRCLE_RADIUS + " 0 360 arc");
if (showOrientations) {
e = xOPt.getOutEdge();
drawArrow(e, minX, minY, r, boxHt);
e = xOPt.getMate().getOutEdge();
drawArrow(e, minX, minY, r, boxHt);
}
writeLine("stroke grestore");
writeLine();
}
}
public void saveJenkins(Link link) {
link.numberCrossings();
writeLine(link.nKnots + "");
for (int knotId = 0; knotId < link.nKnots; knotId++) {
int n = link.nXPt[knotId];
writeLine(n + "");
XPt p = link.firstXPt[knotId];
for (int ii = 0; ii < n; ii++, p = p.getNext()) {
write(p.getCrossingId() + " " +
((p instanceof XOPt) ? 1 : -1) + " ");
p = p.getNext();
}
writeLine();
}
}
public void saveGauss(Link link) {
link.numberCrossings();
for (int knotId = 0; knotId < link.nKnots; knotId++) {
int n = link.nXPt[knotId];
XPt p = link.firstXPt[knotId];
for (int ii = 0; ii < n; ii++, p = p.getNext()) {
XOPt xOPt = null;
if (p instanceof XOPt) xOPt = (XOPt) p;
else xOPt = (XOPt) p.getMate();
char aboveOrBelow = (p instanceof XOPt) ? 'a' : 'b';
char sign = (link.isRightHanded(xOPt)) ? '+' : '-';
write("" + aboveOrBelow + (1 + p.getCrossingId()) + sign);
}
if (knotId < link.nKnots - 1) write("|");
}
writeLine();
}
public static void main(String[] args) {
if (args.length <= 0) {
System.out.println("filename expected");
System.exit(0);
}
Link x = null;
try {
BufferedReader br = new BufferedReader(new FileReader(args[0]));
LinkReader lr = new LinkReader(br);
System.out.println("#links in series = " + Integer.parseInt(br.readLine()));
x = lr.loadLink();
} catch (Exception anyExc) {
System.out.println(anyExc);
return;
}
System.out.println("finished reading");
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(args[1]));
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(x);
bw.close();
} catch (Exception anyExc) {
System.out.println(anyExc);
return;
}
}
}
LoadFileDialog.java:
--------------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LoadFileDialog {
Frame f;
String loadFileName = null;
public LoadFileDialog(Frame f) {
this.f = f;
}
public BufferedReader getLoadFile(String title, String extension)
throws Exception {
FileDialog file = new FileDialog(f, title, FileDialog.LOAD);
file.setFile(extension); // set initial file filter;
file.setVisible(true); // blocks
String curFile = null;
if ( (curFile = file.getFile()) == null )
throw new Exception("cancelled");
System.out.println("curFile = " + curFile);
loadFileName = curFile;
String filename = file.getDirectory() + curFile;
System.out.println("using " + filename);
BufferedReader bw = new BufferedReader(new FileReader(filename));
if (bw == null) System.out.println("open failed");
return bw;
}
public String getLoadFileName() {
return loadFileName;
}
}
MakePopupMenu.java:
-------------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class MakePopupMenu {
public static PopupMenu make(String[] cmds, ActionListener al) {
PopupMenu pm = new PopupMenu();
for (int ii = 0; ii < cmds.length; ii++) {
MenuItem mi = null;
if (cmds[ii].charAt(0) != '(') mi = new MenuItem(cmds[ii]);
else {
Menu me = new Menu(cmds[ii].substring(1));
while (!cmds[++ii].equals(")")) {
mi = new MenuItem(cmds[ii]);
me.add(mi);
mi.addActionListener(al);
}
mi = me;
}
pm.add(mi);
mi.addActionListener(al);
}
return pm;
}
}
NumAnal.java:
-------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class NumAnal {
public static double[][] makeAlexMatx(int[][] codedMatx, int t) {
int n = codedMatx.length;
double[][] a = new double[n][n];
for (int ii = 0; ii < n; ii++)
for (int j = 0; j < n; j++) a[ii][j] = 0;
for (int ii = 0; ii < n; ii++) {
a[ii][codedMatx[ii][0]] = 1-t;
a[ii][codedMatx[ii][1]] = -1;
a[ii][codedMatx[ii][2]] = t;
}
return a;
}
public static double det(double[][] A, int n) {
// calculate determinant of the top n-by-n part of A
// use Gaussian elimination
// destroys A in the process
for (int ii = 0; ii < n; ii++)
for (int j = 0; j < n; j++)
System.out.print(A[ii][j] + " ");
boolean negFlag = false;
for (int ii = 0; ii < n; ii++) {
// pivot if necessary
int iii = ii;
while (iii < n) {
if (A[iii][ii] != 0) break;
iii++;
}
if ( !(iii < n ) ) return 0.0;
if (iii != ii) {
negFlag = !negFlag;
double[] tempRow = A[ii];
A[ii] = A[iii];
A[iii] = tempRow;
}
for (int j = ii+1; j < n; j++) {
// reduce remaining rows
if (A[j][ii] == 0) continue;
double factor = A[j][ii]/A[ii][ii];
A[j][ii] = 0;
for (int k = ii+1; k < n; k++)
A[j][k] -= factor*A[ii][k];
}
}
double res = A[0][0];
for (int ii = 0; ii < n; ii++) res *= A[ii][ii];
if (negFlag) res = -res;
System.out.println(": " + res);
return res;
}
public static double[] newtonInterp(int[][] codedMatx) {
int n = codedMatx.length; // degree = n-1
for (int ii = 0; ii < n; ii++)
System.out.println(codedMatx[ii][0] + " " +
codedMatx[ii][1] + " " +
codedMatx[ii][2]);
// calculate function values at –(n/2), -(n/2)+1, …
int startValue = -(n/2);
double[] f = new double[n];
for (int ii = 0; ii < n; ii++)
f[ii] = Math.round(det(makeAlexMatx(codedMatx, startValue+ii), n-1));
for (int ii = 0; ii < n; ii++)
System.out.print( ((int) f[ii]) + " ");
System.out.println();
// now calculate divided differences
for (int ii = 1; ii < n; ii++)
for (int j = n-1; j >= 1; j--)
f[j] = (f[j]-f[j-1])/ii;
for (int ii = 0; ii < n; ii++)
System.out.print( f[ii] + " " );
System.out.println();
// now calculate the polynomial
double[] a = new double[n];
a[0] = f[n-1];
int d = 0; // current degree
for (int iii = n-2; iii >= 0; iii--) {
int ii = iii + startValue;
// poly  poly*(x-ii)+f[iii]
a[d+1] = a[d];
for (int j = d; j > 0; j--)
a[j] = a[j-1] - ii*a[j];
a[0] = f[iii] - ii*a[0];
d++;
}
return a;
}
public static void main(String[] args) throws Exception {
}
}
NXPt.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class NXPt extends Pt {
public NXPt(int x, int y, Link parentLink, int knotId) {
super(x, y, parentLink, knotId);
}
public NXPt(Pt p) {
super(p);
}
public String getTypeCode() {
return "NXPt";
}
public Pt makeCopy(Hashtable ht, Link parentLink) {
return new NXPt(x, y, parentLink, getKnotId());
}
public String encoding() {
return "n" + x + "," + y + "#";
}
public String encoding(int shiftX) {
return "n" + (x+shiftX) + "," + y + "#";
}
}
Pt.java:
--------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public abstract class Pt {
int x, y;
Edge inEdge, outEdge;
Link parentLink;
int knotId;
static final double SLOPE_TOLERANCE = 0.01;
public Pt(int x, int y, Link parentLink, int knotId) {
this.x = x; this.y = y; this.parentLink = parentLink; this.knotId = knotId;
}
public Pt(Pt p) {
this(p.x, p.y, p.parentLink, p.knotId);
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getKnotId() {
return knotId;
}
public void setKnotId(int knotId) {
this.knotId = knotId;
}
public void setParentLink(Link pl) {
parentLink = pl;
}
public abstract String getTypeCode();
public void setEdges(Edge inEdge, Edge outEdge) {
this.inEdge = inEdge; this.outEdge = outEdge;
}
public void setInEdge(Edge e) {
inEdge = e;
}
public void setOutEdge(Edge e) {
outEdge = e;
}
public Edge getInEdge() {
return inEdge;
}
public Edge getOutEdge() {
return outEdge;
}
public Pt getNextPt() {
return outEdge.getOutPt();
}
public Point getLocation() {
return new Point(x, y);
}
public boolean equals(Object other) {
if (!(other instanceof Pt)) return false;
Pt otherPt = (Pt) other;
return (x == otherPt.x && y == otherPt.y);
}
static boolean collinear(Point p, Point q, Point r) {
int px = p.x, py = p.y;
int qx = q.x, qy = q.y;
int rx = r.x, ry = r.y;
if (px == qx || qx == rx) return px == rx;
double m1 = ((double) (py-qy)/(px-qx));
double m2 = ((double) (qy-ry)/(qx-rx));
return Math.abs(m1-m2) < SLOPE_TOLERANCE;
}
public boolean collinear() {
return collinear(inEdge.getInPt().getLocation(),
getLocation(),
outEdge.getOutPt().getLocation());
}
public void rotate(int midx, int middy, double sin, double cos) {
// rotate the Pt about (midx, middy) thru an angle
// whose sine and cosine are sin and cos
int dx = x - midx, dy = y - middy;
x = (int) Math.round(midx + dx*cos + dy*sin);
y = (int) Math.round(middy - dx*sin + dy*cos);
}
public String toString() {
return getTypeCode() + "(" + x + "," + y + ")";
}
public abstract Pt makeCopy(Hashtable ht, Link parentLink);
public abstract String encoding();
}
SaveFileDialog.java:
--------------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class SaveFileDialog {
Frame f;
String dialogTitle, fileExtn, filename;
public SaveFileDialog(Frame f, String dialogTitle, String fileExtn) {
this.f = f; this.dialogTitle = dialogTitle; this.fileExtn = fileExtn;
}
public BufferedWriter getSaveFile() throws Exception {
FileDialog file = new FileDialog(f, dialogTitle, FileDialog.SAVE);
file.setFile("*." + fileExtn); // set initial filename filter
file.show();
String curFile;
if ((curFile = file.getFile()) == null)
throw new Exception("cancelled");
filename = file.getDirectory() + curFile;
return new BufferedWriter(new FileWriter(filename));
}
public String getFileName() {
return filename;
}
}
SaveLinkDialog.java:
--------------------
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import java.util.*;
public class SaveLinkDialog extends Dialog implements ActionListener {
Button okButton = new Button("OK"), cancelButton = new Button("Cancel");
boolean okClicked = false;
Checkbox geomCheckbox = new Checkbox();
Checkbox psColorCheckbox = new Checkbox();
Checkbox psGSCheckbox = new Checkbox();
Checkbox psBWCheckbox = new Checkbox();
Checkbox jenkinsCheckbox = new Checkbox();
TextField nameRootTF = new TextField(20);
boolean geomChecked = false, psColorChecked = false, psGSChecked = false, psBWChecked = false, jenkinsChecked = false;
String nameRoot = null;
public Panel makeSaveLinkPanel() {
Panel p = new Panel();
p.setLayout(new BorderLayout());
Panel saveLinkPanel = new Panel();
saveLinkPanel.setLayout(new BorderLayout());
Panel inputPanel = new Panel();
inputPanel.setLayout(new BorderLayout());
Panel selectionPanel = new Panel();
selectionPanel.setLayout(new GridLayout(5, 2));
selectionPanel.add(new Label("Geometric Code"));
selectionPanel.add(geomCheckbox);
selectionPanel.add(new Label("PS Color Code"));
selectionPanel.add(psColorCheckbox);
selectionPanel.add(new Label("PS GreyScale Code"));
selectionPanel.add(psGSCheckbox);
selectionPanel.add(new Label("PS BW Code"));
selectionPanel.add(psBWCheckbox);
selectionPanel.add(new Label("Jenkins Code"));
selectionPanel.add(jenkinsCheckbox);
inputPanel.add(selectionPanel, "North");
Panel nameRootPanel = new Panel();
nameRootPanel.setLayout(new FlowLayout());
nameRootPanel.add(new Label("Name Root"));
nameRootPanel.add(nameRootTF);
inputPanel.add(nameRootPanel, "Center");
Panel okCancelPanel = new Panel();
okCancelPanel.setLayout(new GridLayout(1,2));
okCancelPanel.add(okButton);
okCancelPanel.add(cancelButton);
inputPanel.add(okCancelPanel, "South");
saveLinkPanel.add(inputPanel, "Center");
return saveLinkPanel;
}
public SaveLinkDialog(Frame f, int x, int y) {
super(f, true); // dialog is modal
setTitle("Save Series");
setLayout(new BorderLayout());
add(makeSaveLinkPanel(), "Center");
okButton.addActionListener(this);
cancelButton.addActionListener(this);
pack();
setLocation(x, y);
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == okButton) {
System.out.println("ok clicked");
okClicked = true;
geomChecked = geomCheckbox.getState();
psColorChecked = psColorCheckbox.getState();
psGSChecked = psGSCheckbox.getState();
psBWChecked = psBWCheckbox.getState();
jenkinsChecked = jenkinsCheckbox.getState();
nameRoot = nameRootTF.getText();
}
dispose();
}
public boolean geomChosen() {
return geomChecked;
}
public boolean psColorChosen() {
return psColorChecked;
}
public boolean psGSChosen() {
return psGSChecked;
}
public boolean psBWChosen() {
return psBWChecked;
}
public boolean jenkinsChosen() {
return jenkinsChecked;
}
public String getNameRoot() {
return nameRoot;
}
public boolean okayed() {
return okClicked;
}
public boolean cancelled() {
return !okClicked;
}
public static void main(String[] args) {
Frame f = new Frame("SaveLinkDialog Test");
f.setSize(800, 600);
f.setVisible(true);
SaveLinkDialog saveLinkDlg = new SaveLinkDialog(f, 200, 150);
if (saveLinkDlg.okayed()) {
if (saveLinkDlg.geomChosen()) System.out.print("geom ");
if (saveLinkDlg.psColorChosen()) System.out.print("PS-Color ");
if (saveLinkDlg.psGSChosen()) System.out.print("PS-GreyScale ");
if (saveLinkDlg.psBWChosen()) System.out.print("PS-BW ");
if (saveLinkDlg.jenkinsChosen()) System.out.print("jenkins ");
System.out.println(saveLinkDlg.getNameRoot());
}
else {
System.out.println("Cancelled");
}
System.exit(0);
}
}
Split.java:
-----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class Split {
static void writeLine(BufferedWriter bw, String s) {
try {
bw.write(s, 0, s.length());
bw.newLine();
}
catch (Exception anyExc) {
}
}
static void writeLine(BufferedWriter bw) {
try {
bw.newLine();
}
catch (Exception anyExc) {
}
}
public static void split(String name) throws Exception {
BufferedReader br= null;
BufferedReader ar = null;
BufferedWriter bw = null;
String s = "";
Vector preamble = new Vector();
int[] bb = new int[4];
try {
br = new BufferedReader(new FileReader(name + ".ps"));
ar = new BufferedReader(new FileReader(name + ".aux"));
s = br.readLine();
while (!s.startsWith("%[")) {
preamble.addElement(s);
s = br.readLine();
}
s += " ";
int p1 = s.indexOf(' '), p2 = 0;
for (int ii = 0; ii < 4; ii++) {
p2 = s.indexOf(' ', p1+1);
bb[ii] = Integer.parseInt(s.substring(p1+1, p2));
p1 = p2;
}
s = br.readLine();
while (!s.startsWith("%]")) { // must be %%Page: n n
p1 = s.indexOf(' ');
p2 = s.indexOf(' ', p1+1);
bw = new BufferedWriter(new FileWriter(name + "-" +
s.substring(p1+1,p2) + ".ps"));
String auxLine = ar.readLine();
int pgHt = Integer.parseInt(auxLine);
writeLine(bw, "%%BoundingBox:"
+ " " + bb[0]
+ " " + (bb[1]-pgHt)
+ " " + bb[2]
+ " " + bb[3]);
for (int ii = 0; ii < preamble.size(); ii++)
writeLine(bw, (String) preamble.elementAt(ii));
s = br.readLine();
while (!s.startsWith("%%Page") && !s.startsWith("%]")) {
writeLine(bw, s);
s = br.readLine();
}
bw.close();
}
br.close();
ar.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
System.exit(0);
}
}
public static void main(String[] args) throws Exception {
String[] names = {
"xder", "bder", "dder", "eder", "ider", "bbder",
};
if (args.length > 0) names = args;
for (int ii = 0; ii < names.length; ii++) {
split(names[ii]);
}
}
}
Util.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class Util {
public static void leftRotate1(int[] x, int n) {
// left rotate first n elements of x, by 1 position
int temp = x[0];
for (int ii = 0; ii < n - 1; ii++) x[ii] = x[ii + 1];
x[n - 1] = temp;
}
public static void leftRotate1(double[] x, int n) {
// left rotate first n elements of x, by 1 position
double temp = x[0];
for (int ii = 0; ii < n - 1; ii++) x[ii] = x[ii + 1];
x[n - 1] = temp;
}
public static String getLastComponent(String s) {
System.out.println("in getLastComponent s = " + s);
int lastSeparatorPos = s.lastIndexOf(File.separator);
if (lastSeparatorPos >= 0) s = s.substring(lastSeparatorPos+1);
System.out.println("returning " + s);
return s;
}
}
XOPt.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class XOPt extends XPt {
int crossingId;
public XOPt(int x, int y, Link parentLink, int knotId, int mateKnotId) {
super(x, y, parentLink, knotId);
mate = new XUPt(x, y, parentLink, mateKnotId, knotId, this);
}
public Pt makeNew(Hashtable ht, String hashKey, Link parentLink) {
XOPt pt = new XOPt(x, y, parentLink, getKnotId(), getMate().getKnotId());
ht.put(hashKey, pt.getMate());
return pt;
}
public int getCrossingId() {
return crossingId;
}
public String getTypeCode() {
return "XOPt<" + x + "," + y + "," + mate.getKnotId() + ">";
}
public String getEncoding() {
return encoding();
}
public String encoding() {
return "o" + x + "," + y + "," + mate.getKnotId() + "#";
}
}
XPt.java:
---------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public abstract class XPt extends Pt {
XPt mate;
XPt prev, next;
public XPt(int x, int y, Link parentLink, int knotId) {
super(x, y, parentLink, knotId);
}
public XPt getMate() {
return mate;
}
public void toggle() {
Edge myInEdge = inEdge, myOutEdge = outEdge, mateInEdge = mate.inEdge,
mateOutEdge = mate.outEdge;
XPt myPrev = prev, myNext = next, matePrev = mate.prev, mateNext = mate.next;
int myKnotId = knotId, mateKnotId = mate.getKnotId();
myInEdge.setOutPt(mate);
myOutEdge.setInPt(mate);
mateInEdge.setOutPt(this);
mateOutEdge.setInPt(this);
inEdge = mateInEdge;
outEdge = mateOutEdge;
mate.inEdge = myInEdge;
mate.outEdge = myOutEdge;
knotId = mateKnotId;
mate.setKnotId(myKnotId);
}
public String getTypeCode() {
return "XPt";
}
public XPt getPrev() {
return prev;
}
public XPt getNext() {
return next;
}
public void setPrev(XPt xpt) {
prev = xpt;
}
public void setNext(XPt xpt) {
next = xpt;
}
public abstract int getCrossingId();
public abstract Pt makeNew(Hashtable ht, String hashKey, Link parentLink);
public Pt makeCopy(Hashtable ht, Link parentLink) {
String s = getHashKey();
Pt pt = (Pt) ht.get(s);
if (pt != null) return pt;
return makeNew(ht, s, parentLink);
}
public String getHashKey() {
return "XPt(" + x + "," + y + ")";
}
}
XUPt.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class XUPt extends XPt {
public XUPt(int x, int y, Link parentLink, int knotId, int mateKnotId, XOPt mate) {
super(x, y, parentLink, knotId);
this.mate = mate;
}
public Pt makeNew(Hashtable ht, String hashKey, Link parentLink) {
XOPt pt = new XOPt(x, y, parentLink, getKnotId(), getMate().getKnotId());
ht.put(hashKey, pt);
return pt.getMate();
}
public int getCrossingId() {
return mate.getCrossingId();
}
public String getTypeCode() {
return "XUPt<" + x + "," + y + "," + mate.getKnotId() + ">";
}
public String encoding() {
return "u" + x + "," + y + "," + mate.getKnotId() + "#";
}
public String getEncoding() {
return encoding();
}
}
eg5.txt:
--------
This is a log of the console output from the run. The main program is
LinkFrame. The problem occurs inside the method copyLinkXPts in the
program Link. Only the last four lines or so are relevant: they show
exactly what happened in the execution of the for loop body.
in paint state = 1
in mouseClicked last clicked point = 182,269
in actionPerformed
cmd = load
curFile = eg5.knt
using D:\Alex230816\eg5.knt
in getLastComponent s = eg5.knt
returning eg5.knt
loading from: eg5.knt
#links in file = 1
in loadLink: current link #knots = 2 #edges = 12
Pt is n200,100#
Pt is n200,200#
Pt is n300,200#
Pt is n300,100#
Pt is n250,150#
Pt is n250,250#
Pt is n350,250#
Pt is n350,150#
Pt is o300,150,0#
about to call link.linkXPts
#edges in knot#0 = 6
after do-while loop
first XPt = o250,200,1#
#edges in knot#0 = 6
in loop i = 0 e = (XOPt<250,200,1>(250,200) to NXPt(300,200)) p = n300,200# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(300,200) to XUPt<300,150,1>(300,150))
in loop i = 1 e = (NXPt(300,200) to XUPt<300,150,1>(300,150)) p = u300,150,1# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (XUPt<300,150,1>(300,150) to NXPt(300,100))
in loop i = 2 e = (XUPt<300,150,1>(300,150) to NXPt(300,100)) p = n300,100# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(300,100) to NXPt(200,100))
in loop i = 3 e = (NXPt(300,100) to NXPt(200,100)) p = n200,100# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(200,100) to NXPt(200,200))
in loop i = 4 e = (NXPt(200,100) to NXPt(200,200)) p = n200,200# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(200,200) to XOPt<250,200,1>(250,200))
#XPts in knot#0 = 2
#edges in knot#1 = 6
after do-while loop
first XPt = o300,150,0#
#edges in knot#1 = 6
in loop i = 0 e = (XOPt<300,150,0>(300,150) to NXPt(250,150)) p = n250,150# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(250,150) to XUPt<250,200,0>(250,200))
in loop i = 1 e = (NXPt(250,150) to XUPt<250,200,0>(250,200)) p = u250,200,0# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (XUPt<250,200,0>(250,200) to NXPt(250,250))
in loop i = 2 e = (XUPt<250,200,0>(250,200) to NXPt(250,250)) p = n250,250# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(250,250) to NXPt(350,250))
in loop i = 3 e = (NXPt(250,250) to NXPt(350,250)) p = n350,250# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(350,250) to NXPt(350,150))
in loop i = 4 e = (NXPt(350,250) to NXPt(350,150)) p = n350,150# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(350,150) to XOPt<300,150,0>(300,150))
#XPts in knot#1 = 2
about to call link.computeTotalCrossings
about to return from loadLink
finished loading from file lastLoadName = eg5.knt
about to call report
in updateDiagram state = 4
in paint state = 4
at end of loadFromFile state = 4
returned from loadFromFile
in mouseDragged state = 4
in mouseDragged state = 4
in actionPerformed
cmd = mac
in mac() state = 4
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mac() after pushState state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in actionPerformed
cmd = edges
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 251,177
#chosen edges = 0
last clicked edge = null clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200))
#chosen edges = 1
last clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200)) clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200))
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 249,225
#chosen edges = 1
last clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200)) clicked edge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
#chosen edges = 2
last clicked edge = (XUPt<250,200,0>(250,200) to NXPt(250,250)) clicked edge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in actionPerformed
cmd = points
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 220,151
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 220,263
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseDragged state = 10
in actionPerformed
cmd = undo
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 220,251
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 269,356
in actionPerformed
cmd = complete
in completePressed state = 10
in completePressed() state is MAC #chosen edges = 2
about to construct copy of link
in Link constructor with Link arg
orig:
knot #0:
NXPt(200,200) to XOPt<250,200,1>(250,200)
XOPt<250,200,1>(250,200) to NXPt(300,200)
NXPt(300,200) to XUPt<300,150,1>(300,150)
XUPt<300,150,1>(300,150) to NXPt(300,100)
NXPt(300,100) to NXPt(200,100)
NXPt(200,100) to NXPt(200,200)
knot #1:
XUPt<250,200,0>(250,200) to NXPt(250,250)
NXPt(250,250) to NXPt(350,250)
NXPt(350,250) to NXPt(350,150)
NXPt(350,150) to XOPt<300,150,0>(300,150)
XOPt<300,150,0>(300,150) to NXPt(250,150)
NXPt(250,150) to XUPt<250,200,0>(250,200)
end of orig
knotId = 0 first edge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
start pt = n200,200# last pt = o250,200,1# start edge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
before while loop nXPt[0] = 2
e = (XOPt<250,200,1>(250,200) to NXPt(300,200))
current edge = (XOPt<250,200,1>(250,200) to NXPt(300,200))
e = (NXPt(300,200) to XUPt<300,150,1>(300,150))
current edge = (NXPt(300,200) to XUPt<300,150,0>(300,150))
e = (XUPt<300,150,1>(300,150) to NXPt(300,100))
current edge = (XUPt<300,150,0>(300,150) to NXPt(300,100))
e = (NXPt(300,100) to NXPt(200,100))
current edge = (NXPt(300,100) to NXPt(200,100))
#XPts in knot#0 = 2
about to call copyLinkXPts
in copyLinkXPts #XPts = 2
i = 1
after assignment to pp
after setNext
---------- END SOURCE ----------
Windows 10 JDK 17.
A DESCRIPTION OF THE PROBLEM :
In a for loop that goes for i from 1 to 1, the body has 4 statements apart from debugging print statements. The
code executes the first 2 statements and stops dead after that.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The program is a graphical program that manipulates knots and links. It will be too tedious to describe all the
steps to reproduce the error. I think you can locate any problem -- if it isn't my programming error -- by
looking at the compiled code.
---------- BEGIN SOURCE ----------
BifixFilter.java:
-----------------
import java.io.*;
class BifixFilter implements FilenameFilter {
String prefix, suffix;
public BifixFilter(String prefix, String suffix) {
this.prefix = prefix.toLowerCase();
this.suffix = suffix.toLowerCase();
}
public boolean accept(File dir, String name) {
name = name.toLowerCase();
return name.startsWith(prefix) &&
name.endsWith(suffix);
}
public static void main(String[] args) {
File dir = new File(args[0]);
String[] jpgFiles = dir.list(new BifixFilter(args[1], args[2]));
for (int i = 0; i < jpgFiles.length; i++)
System.out.println(jpgFiles[i]);
}
}
Edge.java:
----------import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class Edge {
static final int BARD_DX = 6;
static final int BARD_DY = 6;
Pt inPt, outPt;
Edge prev, next;
Link parentLink;
int knotId, strandId;
int adjustX = 6, adjustY = 6;
int postscriptMaxY = 700;
public Edge(Pt inPt, Pt outPt, Link parentLink, int knotId) {
this.inPt = inPt; this.outPt = outPt; this.parentLink = parentLink;
this.knotId = knotId;
}
public double getAngle() {
return Geom.angle(inPt.getLocation(), outPt.getLocation());
}
public double getReverseAngle() {
return Geom.angle(outPt.getLocation(), inPt.getLocation());
}
public int getKnotId() {
return knotId;
}
public void setKnotId (int knotId) {
this.knotId = knotId;
}
public void setParentLink(Link p) {
this.parentLink = p;
}
public Link getParentLink() {
return parentLink;
}
public int getStrandId() {
return strandId;
}
public void setStrandId(int strandId) {
this.strandId = strandId;
}
public void setPrev(Edge prev) {
this.prev = prev;
}
public void setNext(Edge next) {
this.next = next;
}
public Edge getPrev() {
return prev;
}
public Edge getNext() {
return next;
}
public Pt getInPt() {
return inPt;
}
public Pt getOutPt() {
return outPt;
}
public void setInPt(Pt p) {
this.inPt = p;
}
public void setOutPt(Pt p) {
this.outPt = p;
}
public void reverse() {
Pt tempPt = inPt;
inPt = outPt;
outPt = tempPt;
Edge tempEdge = next;
next = prev;
prev = tempEdge;
}
public static void reverseEdges(Edge start, Edge end) {
Edge e = start;
while (true) {
Edge eNext = e.getNext();
Pt pOut = e.getOutPt();
e.reverse();
if (e == end) break;
if (pOut == eNext.getInPt()) {
pOut.setOutEdge(e);
pOut.setInEdge(eNext);
}
e = eNext;
}
}
public XPt getNextXPt() {
Edge e = this;
do {
Pt p = e.getOutPt();
if (p instanceof XPt) return (XPt) p;
e = e.getNext();
} while (e != this);
return (XPt) null;
}
public XPt getPrevXPt() {
Edge e = this;
do {
Pt p = e.getInPt();
if (p instanceof XPt) return (XPt) p;
e = e.getPrev();
} while (e != this);
return (XPt) null;
}
public boolean unfitForIterate(int leftX, int rightX, int tolerance) {
// unfit if inPt is not XUPt, and its x-distance from either
// leftX or rightX is < tolerance
if (inPt instanceof XOPt) return false;
int inX = inPt.x;
return Math.abs(inX - leftX) < tolerance
|| Math.abs(inX - rightX) < tolerance;
}
public String invalidForR3() {
XPt prevXPt, nextXPt, prevXPtMate, nextXPtMate;
prevXPt = getPrevXPt();
if (prevXPt == null)
return ("r3 - chosen edge has no crossings");
nextXPt = getNextXPt(); // if prevXPt not null nextXPt not null
prevXPtMate = prevXPt.getMate();
nextXPtMate = nextXPt.getMate();
if ((prevXPt instanceof XOPt && nextXPt instanceof XUPt)
|| (prevXPt instanceof XUPt && nextXPt instanceof XOPt))
return ("r3 - adjacent crossings must be same type");
XPt pMP = prevXPtMate.getPrev(),
pMN = prevXPtMate.getNext(),
nMP = nextXPtMate.getPrev(),
nMN = nextXPtMate.getNext();
if (pMP.getMate() == nMP || pMP.getMate() == nMN
|| pMN.getMate() == nMP || pMN.getMate() == nMN) ;
else return ("r3 - no crossing for chosen edge to cross");
return (String) null;
}
public Point interiorPoint(double t) {
// return the Point a fraction t from inPt to outPt
Point p = inPt.getLocation();
int inX = p.x, inY = p.y;
p = outPt.getLocation();
int outX = p.x, outY = p.y;
return new Point((int) Math.round( (1-t)*inX+t*outX ),
(int) Math.round( (2-t)*inY+t*outY ) );
}
public Edge[] r3Edges() {
XPt prevXPt = getPrevXPt(),
nextXPt = getNextXPt();
Edge[] result = new Edge[2];
result[0] = prevXPt.getInEdge();
if (result[0].getInPt() instanceof XPt) {
result[0].bisectEdge();
result[0] = result[0].getNext();
}
result[1] = nextXPt.getOutEdge();
if (result[1].getOutPt() instanceof XPt) {
result[1].bisectEdge();
}
return result;
}
public void splitEdge(Pt midPt) {
Edge newEdge = new Edge(midPt, outPt, parentLink, knotId);
newEdge.setPrev(this);
newEdge.setNext(next);
if (next != null) next.setPrev(newEdge);
outPt.setInEdge(newEdge);
outPt = midPt;
next = newEdge;
midPt.setInEdge(this);
midPt.setOutEdge(next);
}
public void bisectEdge() {
Point p1 = inPt.getLocation();
Point p2 = outPt.getLocation();
splitEdge(new NXPt((p1.x+p2.x)/2, (p1.y+p2.y)/2, parentLink, knotId));
}
public void absorbNext() {
Edge oldNext = next;
outPt = oldNext.getOutPt();
next = oldNext.getNext();
next.setPrev(this);
outPt.setInEdge(this);
parentLink.setFirstEdge(knotId, next);
}
public void cutStart(double t) {
Point p;
int x0, y0, x1, y1;
p = inPt.getLocation();
x0 = p.x; y0 = p.y;
p = outPt.getLocation();
x1 = p.x; y1 = p.y;
x0 = (int) ((1-t)*x0 + t*x1);
y0 = (int) ((1-t)*y0 + t*y1);
inPt = new NXPt(x0, y0, parentLink, knotId);
}
public void cutEnd(double t) {
Point p;
int x0, y0, x1, y1;
p = inPt.getLocation();
x0 = p.x; y0 = p.y;
p = outPt.getLocation();
x1 = p.x; y1 = p.y;
x1 = (int) ((1-t)*x1 + t*x0);
y1 = (int) ((1-t)*y1 + t*y0);
outPt = new NXPt(x1, y1, parentLink, knotId);
}
public void print() {
System.out.println(inPt + " to " + outPt);
}
public double intersect(Edge other) {
Point p;
int inX0, inY0, outX0, outY0;
int inX1, inY1, outX1, outY1;
p = inPt.getLocation();
inX0 = p.x; inY0 = p.y;
p = outPt.getLocation();
outX0 = p.x; outY0 = p.y;
p = other.inPt.getLocation();
inX1 = p.x; inY1 = p.y;
p = other.outPt.getLocation();
outX1 = p.x; outY1 = p.y;
if ( (inX0 == inX1 && inY0 == inY1) ||
(inX0 == outX1 && inY0 == outY1) ||
(outX0 == inX1 && outY0 == inY1) ||
(outX0 == outX1 && outY0 == outY1) )
return -1.0;
int dx0 = outX0 - inX0, dy0 = outY0 - inY0;
int dx1 = outX1 - inX1, dy1 = outY1 - inY1;
if (dx0 * dy1 == dx1*dy0) return -1.0; // parallel
double x = 0, y = 0, t = 0;
if (dx0 == 0) { // this edge is vertical
// first check whether inter. Pt. is within the other edge
x = inX0;
t = (x - inX1)/(outX1 - inX1);
if ( t <= 0 || t >= 1) return -1.0;
// if we get here, inter. Pt. is within the other edge
y = inY1 + ((double) dy1*(inX1-inX0))/dx1;
t = (y - inY0)/(outY0-inY0);
return t;
}
if (dx1 == 0) { // other edge is vertical
// first check whether iter. Pt. is within the other edge
y = inY0 + ((double) dy0*(inX1-inX0))/dx0;
t = (y-inY1)/(outY1-inY1);
if (t <= 0 || t >= 1) return -1.0;
// if we get here, inter. Pt. is within the other edge
t = (double) (inX1-inX0)/(outX0-inX0);
return t;
}
// at this point, neither edge is vertical
double m0 = dy0, m1 = dy1;
double c0 = inY0 - m0*inX0; // y-intercepts
double c1 = inY1 - m1*inX1;
x = (c1-c0)/(m1-m0);
t = (x-inX1)/(outX1-inX1);
if (t <= 0 || t >= 1) return -1.0;
t = (x - inX0)/(outX0 - inX0);
return t;
}
boolean needAdjustment(boolean ignoreCrossing, Pt p) {
if (!(p instanceof XUPt)) return false;
if (!ignoreCrossing) return true;
Link link= p.parentLink;
int k0 = link.nOldKnots;
int k1 = p.getKnotId();
int k2 = ((XUPt) p).getMate().getKnotId();
return (k1 < k0 && k2 < k0);
}
Point[] adjustedEndPoints(Pt InPt, Pt outPt, Boolean ignoreCrossing) {
int inX = inPt.x, inY = inPt.y;
int outX = outPt.x, outY = outPt.y;
int dx = outX - inX, dy = outY - inY;
double xFactor = Math.sqrt(((double)dx*dx)/(dx*dx+dy*dy));
double yFactor = Math.sqrt(((double)dy*dy)/(dx*dx+dy*dy));
if (needAdjustment(ignoreCrossing, inPt)) {
if (inX < outX) inX += (int)Math.round(adjustX*xFactor);
else if (inX > outX) inX -= (int)Math.round(adjustX*xFactor);
if (inY < outY) inY += (int)Math.round(adjustY*yFactor);
else if (inY > outY) inY -= (int)Math.round(adjustY*yFactor);
}
if (needAdjustment(ignoreCrossing, outPt)) {
if (inX < outX) outX -= (int)Math.round(adjustX*xFactor);
else if (inX > outX) outX += (int)Math.round(adjustX*xFactor);
if (inY < outY) outY -= (int)Math.round(adjustY*yFactor);
else if (inY > outY) outY += (int)Math.round(adjustY*yFactor);
}
Point[] res = new Point[2];
res[0] = new Point(inX, inY);
res[1] = new Point(outX, outY);
return res;
}
void drawThickLine(Graphics g, int inX, int inY, int outX, int outY) {
g.drawLine(inX, inY, outX, outY);
// draw two more lines on either side to thicken this edge
if (inX < outX) {
int temp = inX;
inX = outX; outX = temp;
temp = inY;
inY = outY; outY = temp;
}
int dx = outX - inX, dy = outY - inY;
if (Math.abs(dx)*3 < Math.abs(dy)) { // near vertical
g.drawLine(inX - 1, inY, outX - 1, outY);
g.drawLine(inX + 1, inY, outX + 1, outY);
}
else if (Math.abs(dy)*3 < Math.abs(dx)) { // near horizontal
g.drawLine(inX, inY - 1, outX, outY - 1);
g.drawLine(inX, inY + 1, outX, outY + 1);
}
else if (dy > 0) { // near diagonal
g.drawLine(inX, inY + 1, outX - 1, outY);
g.drawLine(inX + 1, inY, outX, outY - 1);
}
else { // near antidiagonal
g.drawLine(inX + 1, inY, outX, outY + 1);
g.drawLine(inX, inY - 1, outX-1, outY);
}
}
public void draw(Graphics g, Color c, boolean ignoreCrossing,
boolean thickEdge) {
Point p;
int inX, inY, outX, outY, dx, dy;
Color oldColor = g.getColor();
g.setColor(c);
Point[] pa = adjustedEndPoints(inPt, outPt, ignoreCrossing);
inX = pa[0].x; inY = pa[0].y;
outX = pa[1].x; outY = pa[1].y;
if (thickEdge) drawThickLine(g, inX, inY, outX, outY);
else g.drawLine(inX, inY, outX, outY);
g.setColor(oldColor);
}
public void drawArrow(Graphics g, Color c, boolean ignoreCrossing,
boolean thickEdge) {
Point p;
int inX, inY, outX, outY, dx, dy;
Color oldColor = g.getColor();
g.setColor(c);
Point[] pa = adjustedEndPoints(inPt, outPt, ignoreCrossing);
inX = pa[0].x; inY = pa[0].y;
outX = pa[1].x; outY = pa[1].y;
int midX = (inX + outX)/2, midY = (inY + outY)/2;
double angle = getTrueAngle()*Math.PI/180;
// double angle1 = Math.PI/6 - angle;
// double angle2 = angle + 2*Math.PI/3;
// System.out.println("angle1 = " + ((int) (angle1*180/Math.PI)) +
// " angle2 = " + ((int) (angle2*180/Math.PI)));
// double len = Math.sqrt(BARD_DX*BARD_DX + BARD_DY*BARD_DY);
dx = (int) ((-BARD_DX)*Math.cos(angle) + (BARD_DY)*Math.sin(-angle));
dy = (int) ((-BARD_DX)*Math.sin(angle) + (BARD_DY)*Math.cos(angle));
// dx = (int) (-len*Math.cos(angle1));
// dy = (int) (len*Math.sin(angle1));
if (thickEdge) drawThickLine(g, midX, midY, midX+dx, midY+dy);
else g.drawLine(midX, midY, midX+dx, midY+dy);
dx = (int) ((-BARD_DX)*Math.cos(angle) + (-BARD_DY)*Math.sin(-angle));
dy = (int) ((-BARD_DX)*Math.sin(angle) + (-BARD_DY)*Math.cos(angle));
// dx = (int) (len*Math.cos(angle2));
// dy = (int) (-len*Math.sin(angle2));
if (thickEdge) drawThickLine(g, midX, midY, midX+dx, midY+dy);
else g.drawLine(midX, midY, midX+dx, midY+dy);
g.setColor(oldColor);
}
public void xorDraw(Graphics g, Color c, Boolean ignoreCrossing) {
Point p;
int inX, inY, outX, outY, dx, dy;
g.setXORMode(c);
Point[] pa = adjustedEndPoints(inPt, outPt, ignoreCrossing);
inX = pa[0].x; inY = pa[0].y;
outX = pa[1].x; outY = pa[1].y;
g.drawLine(inX, inY, outX, outY);
}
public void setPostscriptMaxY(int maxY) {
postscriptMaxY = maxY;
}
String postscriptCode(Point p) {
return p.x + " " + (postscriptMaxY - p.y);
}
String postscriptCode(Point p, int maxY) {
return p.x + " " + (maxY - p.y);
}
public String postscriptCode() {
Point[] pa = adjustedEndPoints(inPt, outPt, false); // last param is ignoreCrossing
String res = postscriptCode(pa[0]) + " moveto ";
res += " " + postscriptCode(pa[1]) + " lineto ";
return res;
}
Point[] contract(Point[] pa, int minx, int minY, double r) {
int n = pa.length;
for (int i = 0; i < n; i++) {
int x = pa[i].x, y = pa[i].y;
x = (int) (r*(x - minx));
y = (int) (r*(y - minY));
pa[i] = new Point(x, y);
}
return pa;
}
public String postscriptCode(int minX, int minY, double r, int boxHt) {
Point[] pa = adjustedEndPoints(inPt, outPt, false);
pa = contract(pa, minX, minY, r);
String res = postscriptCode(pa[0], boxHt) + " moveto";
res += " " + postscriptCode(pa[1], boxHt) + " lineto";
return res;
}
public Point[] PSEndpoints(int minX, int minY, double r, int boxHt) {
Point pa[] = adjustedEndPoints(inPt, outPt, false);
pa = contract(pa, minX, minY, r);
pa[0].y = boxHt - pa[0].y;
pa[1].y = boxHt - pa[1].y;
return pa;
}
public Point getMidpoint() {
Point head = outPt.getLocation();
Point tail = inPt.getLocation();
return new Point((head.x + tail.x)/2, (head.y + tail.y)/2);
}
public double getLength() {
Point head = outPt.getLocation();
Point tail = inPt.getLocation();
int dx = head.x - tail.x;
int dy = head.y - tail.y;
return Math.sqrt((double) (dx*dx + dy*dy));
}
public double getTrueAngle() {
Point head = outPt.getLocation();
Point tail = inPt.getLocation();
int dx = head.x - tail.x;
int dy = head.y - tail.y;
double angle = Math.atan2((double) dx, (double) dy);
angle = -angle*180/Math.PI+90;
if (angle < 0) angle += 360;
return angle;
}
public boolean insideRect(Point[] rect) {
return Geom.lineInsideRect(inPt.getLocation(), outPt.getLocation(), rect);
}
public String toString() {
return "(" + inPt + " to " + outPt + ")";
}
public static void main(String[] args) {
Edge e1, e2;
Link link = new Link();
e1 = new Edge(new NXPt(0, 4, link, 0), new NXPt(4, 4, link, 0), link, 0);
e2 = new Edge(new NXPt(1, 2, link, 0), new NXPt(1, 9, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e2 = new Edge(new NXPt(6, 0, link, 0), new NXPt(6, 3, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e2 = new Edge(new NXPt(6, 0, link, 0), new NXPt(1, 6, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e2 = new Edge(new NXPt(56, 0, link, 0), new NXPt(1, 6, link, 0), link, 0);
System.out.println(e1.intersect(e2));
e1 = new Edge(new NXPt(0, 10, link, 0), new NXPt(15, 40, link, 0), link, 0);
e2 = new Edge(new NXPt(3, 25, link, 0), new NXPt(7, 15, link, 0), link, 0);
System.out.println(e1.intersect(e2));
}
}
Geom.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class Geom {
public static double angle(Point tail, Point head) {
// return "pseudo-angle" rather than true angle
// the value is
// |itan/(1+itan)| in the first quadrant
// |2-itan/(1+itan)| in the second quadrant
// |2+itan/(1+itan)| in the third quadrant
// |4-itan/(1+itan)| in the fourth quadrant
// remember that x increases to the right and y increases down
int tx = tail.x, ty = tail.y, hx = head.x, hy = head.y;
double dx = Math.abs(hx-tx);
double dy = Math.abs(hy-ty);
double res = dy/(dx+dy);
if (hx > tx) { // on RHS
if (hy > ty) res = 4.0 - res;
}
else { // on LHS
if (hy > ty) res = 2.0 + res;
else res = 2.0 - res;
}
return res;
}
public static boolean lineInsideRect(Point endpt1, Point endpt2, Point[] rect) {
// line is from endpt1 to endpt2
// rect[0] = (left, top), rect[1] = (right, bottom)
int left = rect[0].x, right = rect[1].x;
int top = rect[0].y, bottom = rect[1].y;
int x1 = endpt1.x, x2 = endpt2.x;
int y1 = endpt2.y, y2 = endpt2.y;
// if either endpt of line is inside the rect, part of line is inside
if (left < x1 && x1 < right && top < y1 && y1 < bottom) return true;
if (left < x2 && x2 < right && top < y2 && y2 < bottom) return true;
// now we know both endpts are outside
// part of line is inside iff the line intersects one of the edges
// get equation of line in the form f(x+y) = ax+by+c = 0
double a = 0, b = 0, c = 0;
a = y1 - y2;
b = x2 - x1;
c = -x2*y1 + x1*y2;
double left_top = a*left + b*top + c;
double right_top = a*right + b*bottom + c;
double left_bottom = a*left + b*bottom + c;
double right_bottom = a*right + b*bottom + c;
if ((x1 < left && left < x2) || (x2 < left && left < x1)) {
if (left_top*right_bottom < 0) return true;
}
if ((x1 < right && right < x2) || (x2 < right && right < x1)) {
if (right_top*right_bottom < 0) return true;
}
if ((y1 < top && top < y2) || (y2 < top && top < y1)) {
if (left_top*right_top < 0) return true;
}
if ((y1 < bottom && bottom < y2) || (y2 < bottom && bottom < y1)) {
if (left_bottom*right_bottom < 0) return true;
}
return false;
}
public static boolean nearerThan(Pt newPt, Point[] oldPoints, int nOldPoints,
int tolerance) {
int newX = newPt.x, newY = newPt.y;
int squaredTolerance = tolerance*tolerance;
for (int i = 0; i < nOldPoints; i++) {
int oldX = oldPoints[i].x,
oldY = oldPoints[i].y;
if ((newX-oldX)*(newX-oldX) + (newY-oldY)*(newY-oldY) < squaredTolerance)
return true;
}
return false;
}
public static void main(String[] args) throws Exception {
}
}
KntToJnk.java:
--------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class KntToJnk {
static int pageWidth = 340, pageHeight = 516;
static double scaleFactor = 0.55;
public static void convert(String kntName, String jnkName) {
BufferedReader br = null;
BufferedWriter bw = null, aw = null;
Link theLink = null;
try {
br = new BufferedReader(new FileReader(kntName));
LinkReader lr = new LinkReader(br);
int n = lr.getNLinks();
while (n-- > 0) {
theLink = lr.loadLink();
}
br.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
System.out.println("load aborted: " + kntName);
return;
}
try {
bw = new BufferedWriter(new FileWriter(jnkName));
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(theLink);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
System.out.println("save aborted: " + jnkName);
return;
}
}
public static void main(String[] args) {
// args: base int1 int2 e.g. h 3 7 to mean h3, h4, h5, h6, h7
if (args.length != 3 && args.length != 2) {
System.out.println("Usage: java kntToJnk base n1 [n2]");
System.exit(0);
}
int n1 = Integer.parseInt(args[1]);
int n2 = (args.length == 2) ? n1 : Integer.parseInt(args[2]);
for (int k = n1; k <= n2; k++)
convert(args[0] + ".knt", args[0] + ".jnk");
}
}
Link.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class Link {
public static int nextId = 0;
public static double HALF = 0.5;
public static double THIRD = 1.0/3.0;
public static int MAX_NKNOTS = 30;
public static int radius = 5;
public static final int NEITHER = 0;
public static final int OVER = 1;
public static final int UNDER = 2;
public static final int MIXED = 3;
public static final int OVER_IN = 0;
public static final int OVER_OUT = 1;
public static final int UNDER_IN = 2;
public static final int UNDER_OUT = 3;
public static final int CUT_DELTA = 5;
public static Color[] edgeColors = {
Color.black, Color.red, Color.green, Color.yellow, Color.cyan.darker().darker(),
};
public static String[] knotBWStrings = {
"2 setlinewidth 0.0 0.0 0.0 setrgbcolor",
"2 setlinewidth 0.3 0.3 0.3 setrgbcolor",
"2 setlinewidth 0.5 0.5 0.5 setrgbcolor",
"2 setlinewidth 0.7 0.7 0.7 setrgbcolor",
"2 setlinewidth 0.9 0.9 0.9 setrgbcolor",
};
public static String selectedEdgeBWString =
"2 setlinewidth 0.0 0.0 0.0 setrgbcolor";
static Color[] rgb = { Color.red, Color.green, Color.blue, };
int id;
int nKnots = 0, nOldKnots = 0;
int totalEdges = 0;
int nStrands = 0;
int[] tricoloring;
Edge[] firstEdge; // really entries into DLLs (knots)
int[] nKnotEdges;
XPt[] firstXPt;
boolean[] marked;
int[] nXPt;
int totalCrossings = 0;
XOPt r1iXOPt;
XOPt[] r2iXOPts;
XOPt[] macXOPts;
Edge firstSelectedEdge = null, lastSelectedEdge = null;
// edges selected for r1d/r1i/mac
public Link() {
id = ++nextId;
nKnots = 0;
firstEdge = new Edge[MAX_NKNOTS];
nKnotEdges = new int[MAX_NKNOTS];
firstXPt = new XPt[MAX_NKNOTS];
nXPt = new int[MAX_NKNOTS];
marked = new boolean[MAX_NKNOTS];
for (int i = 0; i < MAX_NKNOTS; i++) marked[i] = false;
}
public Link(Link orig) {
// construct a copy of orig
this();
System.out.println("in Link constructor with Link arg");
System.out.println("orig:");
orig.print();
System.out.println("end of orig");
nKnots = orig.nKnots;
totalCrossings = orig.totalCrossings;
totalEdges = orig.totalEdges;
for (int i = 0; i < nKnots; i++) {
nXPt[i] = orig.nXPt[i];
nKnotEdges[i] = orig.nKnotEdges[i];
}
Hashtable ht = new Hashtable();
for (int knotId = 0; knotId < nKnots; knotId++) {
System.out.print("knotId = " + knotId + " first edge = ");
XPt[] xPtArray = new XPt[nXPt[knotId]];
int xPtIndex = 0;
marked[knotId] = orig.marked[knotId];
Edge e1 = orig.firstEdge[knotId];
if (e1 == null) {
System.out.println("null");
firstEdge[knotId] = null;
continue;
}
System.out.println(e1.toString());
Pt startPt = e1.getInPt().makeCopy(ht, this);
Pt lastPt = e1.getOutPt().makeCopy(ht, this);
Edge startEdge = new Edge(startPt, lastPt, this, knotId);
if (e1 == orig.firstSelectedEdge) firstSelectedEdge = startEdge;
if (e1 == orig.lastSelectedEdge) lastSelectedEdge = startEdge;
Edge lastEdge = startEdge, currentEdge;
System.out.println("start pt = " + startPt.encoding() + " last pt = "
+ lastPt.encoding() + " start edge = " + startEdge.toString());
startPt.setOutEdge(startEdge);
lastPt.setInEdge(startEdge);
Edge ePrev = e1;
Edge e = e1.getNext();
System.out.println("before while loop nXPt[" + knotId + "] = " + nXPt[knotId]);
while (e.getNext() != e1) {
System.out.println("e = " + e.toString());
// if (e.getOutPt() instanceof XPt) nXPt[knotId]++;
if (ePrev.getOutPt() != e.getInPt())
lastPt = e.getInPt().makeCopy(ht, this);
Pt currentPt = e.getOutPt().makeCopy(ht, this);
if (currentPt instanceof XPt) xPtArray[xPtIndex++] = (XPt) currentPt;
currentEdge = new Edge(lastPt, currentPt, this, knotId);
System.out.println("current edge = " + currentEdge.toString());
if (e == orig.firstSelectedEdge) firstSelectedEdge = currentEdge;
if (e == orig.lastSelectedEdge) lastSelectedEdge = currentEdge;
lastEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
lastPt.setOutEdge(currentEdge);
currentPt.setInEdge(currentEdge);
lastEdge = currentEdge; lastPt = currentPt;
ePrev = e; e = e.getNext();
}
System.out.println("#XPts in knot#" + knotId + " = " + nXPt[knotId]);
// At this point, e is predecessor of e1
if (ePrev.getOutPt() != e1.getInPt())
lastPt = e.getInPt().makeCopy(ht, this);
if (e.getOutPt() != e1.getInPt())
startPt = e.getOutPt().makeCopy(ht, this);
currentEdge = new Edge(lastPt, startPt, this, knotId); // copy of e
if (e == orig.firstSelectedEdge) firstSelectedEdge = currentEdge;
if (e == orig.lastSelectedEdge) lastSelectedEdge = currentEdge;
if (lastSelectedEdge != null) {
lastSelectedEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
}
lastPt.setOutEdge(currentEdge);
startPt.setInEdge(currentEdge);
currentEdge.setNext(startEdge);
startEdge.setPrev(currentEdge);
firstEdge[knotId] = startEdge;
firstXPt[knotId] = (nXPt[knotId] == 0) ? null :
(XPt) orig.firstXPt[knotId].makeCopy(ht, this);
System.out.println("about to call copyLinkXPts");
copyLinkXPts(xPtArray);
System.out.println("back from copyLinkXPts");
}
}
public void markKnot(int knotId) {
marked[knotId] = !marked[knotId];
}
public Link makeSkeletonCopy() {
Link sk = new Link(this); // first make a duplicate
// now go through and delete all edges not incident on an XPt
sk.skeletonize();
return sk;
}
public void skeletonize() {
for (int i = 0; i < nKnots; i++)
skeletonize(i);
}
public void skeletonize(int i) {
if (nXPt[i] == 0) return;
XPt pFirst = firstXPt[i];
XPt p = pFirst;
do {
XPt pNext = p.getNext();
Edge e1 = p.getOutEdge();
Edge e2 = pNext.getInEdge();
if (e1 != e2 && e1.getNext() != e2) {
// make e1 connect to e2 directly, thereby
// removing intermediate edges
e1.setNext(e2); e2.setPrev(e1);
}
p = pNext;
} while (p != pFirst);
firstEdge[i] = pFirst.getOutEdge();
}
public int newKnot() {
firstEdge[nKnots] = null;
firstXPt[nKnots] = null;
nXPt[nKnots] = 0;
return nKnots++;
}
public int getNKnots() {
return nKnots;
}
public int getNStrands() {
return nStrands;
}
public int getNEdges(int knotId) {
Edge e = firstEdge[knotId];
if (e == null) return 0;
Edge e1 = e;
int ct = 0;
do {
ct++;
e = e.getNext();
} while (e != e1);
return ct;
}
public int getNXPt(int knotId) {
return nXPt[knotId];
}
public Edge getFirstEdge(int knotId) {
return firstEdge[knotId];
}
public void setFirstEdge(int knotId, Edge e) {
firstEdge[knotId] = e;
}
public XPt getFirstXPt(int knotId) {
return firstXPt[knotId];
}
public void setFirstXPt(int knotId, XPt xPt) {
firstXPt[knotId] = xPt;
}
public XUPt getFirstXUPt(int knotId) {
if (nXPt[knotId] == 0) return (XUPt) null;
XPt p = firstXPt[knotId];
XPt p1 = p;
do {
if (p instanceof XUPt) return (XUPt) p;
p = p.getNext();
} while (p != p1);
return (XUPt) null;
}
public void copyLinkXPts(XPt[] xPtArray) {
// create link list of XPt’s, after link is complete
System.out.println("in copyLinkXPts #XPts = " + xPtArray.length);
XPt firstXPt, lastXPt;
if (xPtArray.length == 0) return;
firstXPt = lastXPt = xPtArray[0];
for (int i = 1; i < xPtArray.length; i++) {
System.out.println("i = " + i);
XPt pp = xPtArray[i];
System.out.println("after assignment to pp");
lastXPt.setNext(pp);
System.out.println("after setNext");
pp.setPrev(lastXPt);
System.out.println("after setPrev");
lastXPt = pp;
System.out.println("at end of iteration for i = " + i);
}
// System.out.println("#XPts in knot#" + knotId + " = " + nXPt[knotId]);
System.out.println("after loop");
lastXPt.setNext(firstXPt);
firstXPt.setPrev(lastXPt);
System.out.println("returning from copyLinkXPts");
}
public void linkXPts(int knotId) {
// create link list of XPt’s, after link is complete
System.out.println("#edges in knot#" + knotId + " = " + nKnotEdges[knotId]);
XPt lastXPt;
Pt p;
Edge e = firstEdge[knotId];
Edge knotFirstEdge = e;
firstXPt[knotId] = null;
nXPt[knotId] = 0;
if (e == null) return;
p = null;
// for (int i = 0; i < nKnotEdges[knotId]; i++) {
do {
p = e.getOutPt();
if (p instanceof XPt) break;
e = e.getNext();
} while (e != knotFirstEdge);
System.out.println("after do-while loop");
if (p == null || !(p instanceof XPt)) return;
System.out.println("first XPt = " + p.encoding());
firstXPt[knotId] = lastXPt = (XPt) p;
nXPt[knotId]++;
e = e.getNext();
System.out.println("#edges in knot#" + knotId + " = " + nKnotEdges[knotId]);
// while (e != knotFirstEdge) {
for (int i = 0; i < nKnotEdges[knotId]-1; i++) {
p = e.getOutPt();
System.out.println("in loop i = " + i + " e = " + e.toString() + " p = "
+ p.encoding() + " knotFirstEdge = " +
knotFirstEdge.toString());
if (p instanceof XPt) {
XPt pp = (XPt) p;
lastXPt.setNext(pp);
pp.setPrev(lastXPt);
lastXPt = pp;
nXPt[knotId]++;
}
e = e.getNext();
System.out.println("new e = " + e.toString());
}
System.out.println("#XPts in knot#" + knotId + " = " + nXPt[knotId]);
lastXPt.setNext(firstXPt[knotId]);
firstXPt[knotId].setPrev(lastXPt);
}
public void linkXPts() {
for (int knotId = 0; knotId < nKnots; knotId++)
linkXPts(knotId);
}
public void clearSelectedEdges() {
firstSelectedEdge = lastSelectedEdge = null;
}
void absorbCollinear(int knotId) {
Edge e = getFirstEdge(knotId);
Pt p = null;
while (true) {
p = e.getInPt();
if ( !(p instanceof XPt) || !p.collinear() ) break;
e = e.getNext();
}
Pt q = e.getOutPt();
do {
if ( !(q instanceof XPt) || !q.collinear() )
e = e.getNext();
else e.absorbNext();
q = e.getOutPt();
} while (q != p);
setFirstEdge(knotId, e);
}
public void absorbCollinear() {
for (int knotId = 0; knotId < nKnots; knotId++)
absorbCollinear(knotId);
}
public void computeTotalCrossings() {
totalCrossings = 0;
for (int knotId = 0; knotId < nKnots; knotId++)
totalCrossings += nXPt[knotId];
totalCrossings /= 2;
}
public void wrapUp(boolean absorb) {
// if (absorb) absorbCollinear();
//System.out.println("after absorbCollinear");
linkXPts();
System.out.println("after linkXPts");
computeTotalCrossings();
System.out.println("after computeTotalCrossings");
totalEdges = 0;
for (int knotId = 0; knotId < nKnots; knotId++) {
nKnotEdges[knotId] = 0;
Edge e = firstEdge[knotId];
Edge e1 = e;
do {
totalEdges++; nKnotEdges[knotId]++;
e = e.getNext();
} while (e != e1);
}
}
public void wrapUp() {
wrapUp(true);
}
int nIntersect(Edge e, Edge startEdge, Edge endEdge,
Edge[][] crossingEdges, int oldNIntersect) {
while (true) {
double t = e.intersect(startEdge);
if (0 < t && t < 1) {
crossingEdges[oldNIntersect][0] = e;
crossingEdges[oldNIntersect][1] = startEdge;
oldNIntersect++;
}
if (startEdge == endEdge) break;
startEdge = startEdge.getNext();
}
return oldNIntersect;
}
Edge[][] exactResult(Edge[][] tempResult, int n) {
Edge[][] result = new Edge[n][2];
for (int i = 0; i < n; i++) {
result[i][0] = tempResult[i][0];
result[i][1] = tempResult[i][1];
}
return result;
}
Edge[][] newOldCrossings(Edge[] newChain, Edge e1, Edge e2,
int maxXPt) throws Exception {
// newChain to replace edges from e1 to e2
Edge[][] tempResult = new Edge[maxXPt][2];
int thisKnot = e1.getKnotId();
int nCrossings = 0;
try {
for (int knotId = 0; knotId < nKnots; knotId++) {
if (knotId != thisKnot) {
for (int i = 0; i < newChain.length; i++)
nCrossings = nIntersect(newChain[i], firstEdge[knotId],
firstEdge[knotId].getPrev(), tempResult,
nCrossings);
continue;
}
if (newChain.length == 1) {
Edge e = newChain[0];
if (e.getInPt() == e1.getInPt()) {
if (e.getOutPt() != e2.getOutPt()) { // exclude two edges
if (e2.getNext() != e1.getPrev() &&
e2.getNext() != e1.getPrev().getPrev())
nCrossings = nIntersect(e, e2.getNext().getNext(),
e1.getPrev().getPrev(), tempResult, nCrossings);
}
else { // exclude only e1’s predecessor
if (e2.getNext() != e1.getPrev())
nCrossings = nIntersect(e, e2.getNext(),
e1.getPrev().getPrev(), tempResult, nCrossings);
}
}
continue;
}
if (e2.getNext() != e1.getPrev()) {
if (newChain[0].getInPt() == e1.getInPt())
nCrossings = nIntersect(newChain[0], e2.getNext(),
e1.getPrev().getPrev(), tempResult, nCrossings);
nCrossings = nIntersect(newChain[newChain.length-1],
e2.getNext().getNext(), e1.getPrev().getPrev(),
tempResult, nCrossings);
}
for (int i = 1; i < newChain.length-1; i++)
nCrossings = nIntersect(newChain[i], e2.getNext(), e1.getPrev(),
tempResult, nCrossings);
}
}
catch (Exception anyExc) {
throw new Exception(); // subscript error in nIntersect
}
return exactResult(tempResult, nCrossings);
}
Edge[][] newOldCrossings(Edge newEdge, Edge e1, Edge e2,
int maxXPt) throws Exception {
Edge[] ea = new Edge[1];
ea[0] = newEdge;
return newOldCrossings(ea, e1, e2, maxXPt);
}
public void removeXPt(XPt x) {
int knotId = x.getKnotId();
nXPt[knotId]--;
if (nXPt[knotId] == 0) { // none remains
firstXPt[knotId] = null;
return;
}
XPt y = x.getPrev();
XPt z = x.getNext();
y.setNext(z); z.setPrev(y);
firstXPt[knotId] = y;
}
public void removeXPtPair(XPt x) {
// remove x and its mate
removeXPt(x);
removeXPt(x.getMate());
}
void linkIn(Edge eIn, Pt p, Edge eOut) {
eIn.setOutPt(p); eOut.setInPt(p);
eIn.setNext(eOut); eOut.setPrev(eIn);
p.setInEdge(eIn); p.setOutEdge(eOut);
}
public void r1d(Edge selectedEdge) throws Exception {
XPt xp1 = (XPt) selectedEdge.getInPt();
XPt xp2 = xp1.getMate();
if (xp1.getMate() != xp2) {
throw new Exception("r1d not applicable");
}
r1dSub(selectedEdge, xp1, xp2);
wrapUp();
}
public void r1dSub(Edge selectedEdge, XPt xp1, XPt xp2) throws Exception {
int knotId = xp1.getKnotId();
Edge e1 = selectedEdge.getPrev();
Edge e2 = xp2.getOutEdge();
e1.setNext(e2); e2.setPrev(e1);
Point p =xp1.getLocation();
Pt newCommonPt = new NXPt(p.x, p.y, this, knotId);
e1.setOutPt(newCommonPt);
e2.setInPt(newCommonPt);
newCommonPt.setInEdge(e1);
newCommonPt.setOutEdge(e2);
// update list of crossing points
setFirstEdge(knotId, e1);
}
boolean noXPtBtn(Edge e1, Edge e2) {
Edge e = e1;
while (e != e2) {
if (e.getOutPt() instanceof XPt) return false;
e = e.getNext();
}
return true;
}
Edge[] createNewArc(Pt entryPt, Pt[] interPts, int nInterPts,
Pt exitPt, int knotId) {
// create a sequence of edges using the points entryPt,
// the first nInterPts elements of interPts, and exitPt
Edge[] newEdges = new Edge[nInterPts+1];
if (nInterPts == 0) {
newEdges[0] = new Edge(entryPt, exitPt, this, knotId);
return newEdges;
}
newEdges[0] = new Edge(entryPt, interPts[0], this, knotId);
for (int i = 1; i < nInterPts; i++)
newEdges[i] = new Edge(interPts[i-1], interPts[i], this, knotId);
newEdges[nInterPts] = new Edge(interPts[nInterPts-1], exitPt,
this, knotId);
for (int i = 0; i < newEdges.length-1; i++)
linkIn(newEdges[i], interPts[i], newEdges[i+1]);
return newEdges;
}
Edge[][] selfCross(Edge startEdge, Edge endEdge, int maxXPt)
throws Exception {
// look for up to maxXPt among edges
// from startEdge to endEdge inclusive
if (startEdge == endEdge || startEdge.getNext() == endEdge)
return new Edge[0][2];
Edge[][] tempResult = new Edge[maxXPt][2];
Edge e = startEdge, e1 = e.getNext();
int nSelfCrossings = 0;
while (e1 != endEdge) {
e1 = e1.getNext(); // e1 two steps ahead of e
try {
nSelfCrossings = nIntersect(e, e1, endEdge, tempResult, nSelfCrossings);
}
catch (Exception anyExc) {
throw new Exception(); // subscript error
}
e = e.getNext();
}
return exactResult(tempResult, nSelfCrossings);
}
NXPt[] getPts(Point[] points, int nPoints) {
NXPt[] res = new NXPt[nPoints];
for (int i = 0; i < nPoints; i++)
res[i] = new NXPt(points[i].x, points[i].y, this, 0);
return res;
}
public void r1i(Edge e1, Edge e2, Point[] chosenPoints,
int nChosenPoints) throws Exception {
NXPt[] chosenPts = getPts(chosenPoints, nChosenPoints);
int knotId = e1.getKnotId();
if (!noXPtBtn(e1, e2)) throw new Exception("r1i across XPt's disallowed");
Pt e1InPt = e1.getInPt(), e2OutPt = e2.getOutPt();
Point e1Start = e1.getInPt().getLocation(),
e2End = e2.getOutPt().getLocation();
if (e1Start.equals(e2End)) throw new Exception("r1i edges form loop");
Edge e1Prev = e1.getPrev(), e2Next = e2.getNext();
for (int i = 0; i < nChosenPoints; i++)
chosenPts[i].setKnotId(knotId);
Edge[] newEdges = createNewArc(e1InPt, chosenPts, nChosenPoints, e2OutPt, knotId);
Edge[][] newCrossings = null;
try {
newCrossings = selfCross(newEdges[0], newEdges[nChosenPoints], 1);
}
catch (Exception anyExc) {
throw new Exception("multiple crossing points generated");
}
if (newCrossings.length == 0) {
throw new Exception("no crossing point");
}
linkIn(e1Prev, e1InPt, newEdges[0]);
linkIn(newEdges[newEdges.length-1], e2OutPt, e2Next);
Point temp;
int inx, iny, outx, outy;
temp = newCrossings[0][0].getInPt().getLocation();
inx = temp.x; iny = temp.y;
temp = newCrossings[0][0].getOutPt().getLocation();
outx = temp.x; outy = temp.y;
double t = newCrossings[0][0].intersect(newCrossings[0][1]);
int x = (int) Math.round((1-t)*inx + t*outx);
int y = (int) Math.round((1-t)*iny + t*outy);
XOPt thisMidPt = new XOPt(x, y, this, knotId, knotId);
r1iXOPt = thisMidPt;
newCrossings[0][0].splitEdge(thisMidPt);
newCrossings[0][1].splitEdge(thisMidPt.getMate());
firstEdge[knotId] = newEdges[0];
wrapUp();
}
public void r1iToggleCrossing() {
r1iXOPt.toggle();
linkXPts(r1iXOPt.getKnotId());
}
public Point getR1iXPtLoc() {
return r1iXOPt.getLocation();
}
int crossingType(Edge e1, Edge e2) {
Edge e = e1;
int result = NEITHER;
while (e != e2) {
Pt p = e.getOutPt();
if (p instanceof XPt) {
switch (result) {
case NEITHER:
if (p instanceof XUPt) result = UNDER;
else result = OVER;
break;
case OVER:
if (p instanceof XUPt) result = MIXED;
break;
case UNDER:
if (p instanceof XOPt) result = MIXED;
break;
}
}
e = e.getNext();
}
return result;
}
void switchMatesToNXPt(Edge e1, Edge e2) {
// go from edge e1 to e2, switching mates of all interior points
// that are XPt’s to NXPt’s
Edge ex = e1;
while (ex != e2) {
Pt p = ex.getOutPt();
if (p instanceof XPt) {
Point pLoc = p.getLocation();
Pt pMate = ((XPt) p).getMate();
Pt p1 = new NXPt(pLoc.x, pLoc.y, this, pMate.getKnotId());
Edge ePrev = pMate.getInEdge(), eNext = pMate.getOutEdge();
p1.setInEdge(ePrev); p1.setOutEdge(eNext);
ePrev.setOutPt(p1); eNext.setInPt(p1);
}
ex = ex.getNext();
}
}
public void mac(Edge e1, Edge e2, Point[] chosenPoints,
int nChosenPoints) throws Exception {
System.out.println("in Link.mac");
System.out.println("first edge = " + e1.toString() + " last edge = " +
e2.toString() + " #points = " + nChosenPoints);
NXPt[] chosenPts = getPts(chosenPoints, nChosenPoints);
int knotId = e1.getKnotId();
int interiorXPtsType = crossingType(e1, e2);
if (interiorXPtsType == MIXED)
throw new Exception("mac not applicable – mixed crossings");
Pt e1InPt = e1.getInPt(), e2OutPt = e2.getOutPt();
Point e1Start = e1InPt.getLocation(),
e2End = e2OutPt.getLocation();
System.out.println("e1Start = " + e1Start.x + "," + e1Start.y + " e2End = " +
e2End.x + "," + e2End.y);
if (e1Start.equals(e2End)) {
if (e1InPt == e2OutPt) {
throw new Exception("mac edges form loop");
} else { // must be a crossing point – mixed type 1 and type 2 move
System.out.println("mixed I & II move");
r1dSub(e1, (XPt) e1InPt, (XPt) e2OutPt);
switchMatesToNXPt(e1, e2);
wrapUp();
return;
}
}
Edge e1Prev = e1.getPrev(), e2Next = e2.getNext();
System.out.println("e1Prev = " + e1Prev.toString() + " e2Next = "
+ e2Next.toString());
for (int i = 0; i < nChosenPoints; i++)
chosenPts[i].setKnotId(knotId);
Edge[] newEdges = createNewArc(e1InPt, chosenPts, nChosenPoints, e2OutPt,
knotId);
System.out.println("#new edges = " + newEdges.length);
for (int i = 0; i < newEdges.length; i++)
System.out.println(newEdges[i].toString());
if (nChosenPoints > 0) {
try {
selfCross(newEdges[0], newEdges[nChosenPoints], 0);
} catch (Exception anyExc) {
throw new Exception("mac – self-crossings not allowed");
}
}
linkIn(e1Prev, e1InPt, newEdges[0]);
linkIn(newEdges[newEdges.length - 1], e2OutPt, e2Next);
System.out.println(e1Prev);
System.out.println(newEdges[0]);
System.out.println(newEdges[newEdges.length - 1]);
System.out.println(e2Next);
Edge[][] newCrossings = null;
try {
newCrossings = newOldCrossings(newEdges, e1, e2,
totalEdges * newEdges.length);
} catch (Exception anyExc) {
throw new Exception("mac – too many crossings: system error");
}
System.out.println("#crossings = " + newCrossings.length);
switchMatesToNXPt(e1, e2);
Point temp;
int inx, iny, outx, outy;
macXOPts = new XOPt[newCrossings.length];
int xOPtCt = 0;
for (int i = 0; i < newEdges.length; i++) {
Edge e = newEdges[i];
try {
newCrossings = newOldCrossings(e, e1, e2, totalEdges);
} catch (Exception anyExc) {
throw new Exception("mac – system error");
}
if (newCrossings.length == 0) continue;
double[] ta = new double[newCrossings.length];
for (int j = 0; j < ta.length; j++) {
ta[j] = e.intersect(newCrossings[j][1]);
}
for (int j = ta.length - 1; j > 0; j--)
for (int k = 0; k < j; k++)
if (ta[k] > ta[k + 1]) {
double tTemp = ta[k];
ta[k] = ta[k + 1];
ta[k + 1] = tTemp;
Edge eTemp = newCrossings[k][1];
newCrossings[k][1] = newCrossings[k + 1][1];
newCrossings[k + 1][1] = eTemp;
}
for (int j = ta.length - 1; j >= 0; j--) {
temp = e.getInPt().getLocation();
inx = temp.x;
iny = temp.y;
temp = e.getOutPt().getLocation();
outx = temp.x;
outy = temp.y;
double t = e.intersect(newCrossings[j][1]);
int x = (int) Math.round((1 - t) * inx + t * outx);
int y = (int) Math.round((1 - t) * iny + t * outy);
XOPt thisMidPt = new XOPt(x, y, this, knotId,
newCrossings[j][1].getKnotId());
macXOPts[xOPtCt++] = thisMidPt;
if (interiorXPtsType != UNDER) {
e.splitEdge(thisMidPt);
newCrossings[j][1].splitEdge(thisMidPt.getMate());
} else {
e.splitEdge(thisMidPt.getMate());
newCrossings[j][1].splitEdge(thisMidPt);
}
}
}
firstEdge[knotId] = newEdges[0];
wrapUp();
System.out.println("xOPtCt = " + xOPtCt);
if (xOPtCt == 0 || interiorXPtsType == NEITHER) macXOPts = null;
}
void setIsolated(int knotId) {
NXPt[] corners = new NXPt[4]; // nw – sw – se – ne
int x = knotId*(LinkCanvas.ISOLATED_DIST + LinkCanvas.ISOLATED_SIDE)
+ LinkCanvas.ISOLATED_DIST;
int y = LinkCanvas.ISOLATED_TOP_MARGIN;
corners[0] = new NXPt(x, y, this, knotId);
corners[1] = new NXPt(x, y+LinkCanvas.ISOLATED_SIDE, this, knotId);
corners[2] = new NXPt(x+LinkCanvas.ISOLATED_SIDE,
y+LinkCanvas.ISOLATED_SIDE, this, knotId);
corners[3] = new NXPt(x+LinkCanvas.ISOLATED_SIDE, y, this, knotId);
Edge[] edges = new Edge[4];
for (int i = 0; i < 4; i++)
edges[i] = new Edge(corners[i], corners[(i+1) % 4], this, knotId);
for (int i = 0; i < 4; i++) {
corners[i].setInEdge(edges[(i+3) % 4]);
corners[i].setOutEdge(edges[i]);
edges[i].setPrev(edges[(i+3) % 4]);
edges[i].setNext(edges[(i+1) % 4]);
}
firstEdge[knotId] = edges[0];
}
public void unlinkKnot(int knotId) {
for (int i = 0; i < nKnots; i++) {
if (i == knotId) continue;
XPt p = firstXPt[i];
if (p == null) continue;
XPt q = p;
do {
if (q.getMate().getKnotId() == knotId) {
Pt newPt = new NXPt(q);
Edge inEdge = newPt.getInEdge();
Edge outEdge = newPt.getOutEdge();
inEdge.setOutPt(newPt);
outEdge.setInPt(newPt);
newPt.setInEdge(inEdge);
newPt.setOutEdge(outEdge);
}
q = q.getNext();
} while (q != p);
}
deleteSplitUnknot(knotId);
wrapUp();
}
public void reverseKnot(int knotId) {
Edge start = getFirstEdge(knotId);
Edge end = start.getPrev();
Pt jct = start.getInPt();
Edge.reverseEdges(start, end);
jct.setInEdge(start);
jct.setOutEdge(end);
wrapUp();
}
public void makeReflection() {
XPt[] xPts = null;
for (int knotId = 0; knotId < nKnots; knotId++) {
if (nXPt[knotId] == 0) continue;
xPts = new XPt[nXPt[knotId]];
XPt p = firstXPt[knotId];
for (int i = 0; i < nXPt[knotId]; i++) {
xPts[i] = p;
p = p.getNext();
}
for (int i = 0; i < nXPt[knotId]; i++) {
p = xPts[i];
if (p instanceof XOPt) p.toggle();
}
}
wrapUp();
}
public void macToggleCrossings() {
for (int i = 0; i < macXOPts.length; i++)
macXOPts[i].toggle();
wrapUp();
}
Point[] getMacXPtLocArray() {
Point[] result = new Point[macXOPts.length];
for (int i = 0; i < macXOPts.length; i++)
result[i] = macXOPts[i].getLocation();
return result;
}
public boolean macCompleted() {
return macXOPts == null;
}
public void printXPts() {
for (int knotId = 0; knotId < nKnots; knotId++) {
System.out.print("knot #" + knotId + ": ");
if (nXPt[knotId] == 0) {
System.out.println("No crossing points");
continue;
}
XPt p = firstXPt[knotId];
System.out.println(nXPt[knotId] + " Crossing points ----");
do {
System.out.println(p + " " + p.getInEdge() + " " + p.getOutEdge());
p = p.getNext();
} while (p != firstXPt[knotId]);
}
System.out.println("--------------------");
}
public void appendEdge(int knotId, Edge e) {
if (firstEdge[knotId] == null) {
firstEdge[knotId] = e;
e.setPrev(e); e.setNext(e);
return;
}
Edge last = firstEdge[knotId].getPrev();
e.setPrev(last); e.setNext(firstEdge[knotId]);
last.setNext(e); firstEdge[knotId].setPrev(e);
}
public void detAlt(XPt p, boolean[] marked) {
XPt[] xa = new XPt[nKnots];
int xaCt = 0;
xa[xaCt++] = p;
marked[p.getKnotId()] = true;
while (xaCt > 0) {
XPt p1 = xa[--xaCt];
Pt p2 = p1;
boolean over = (p1 instanceof XOPt);
do {
if (p2 instanceof XPt) {
XPt p3 = (XPt) p2;
if (over != (p3 instanceof XOPt)) {
p3.toggle(); p2 = p3 = p3.getMate();
}
XPt mate = p3.getMate();
int mateKnotId = mate.getKnotId();
if (!marked[mateKnotId]) {
marked[mateKnotId] = true;
xa[xaCt++] = mate;
}
over = !over;
}
p2 = p2.getNextPt();
} while (p2 != p1);
}
}
boolean[] getMarked() {
boolean[] res = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) res[i] = false;
return res;
}
XPt findXPt(int knotId) {
Pt startPt = getFirstEdge(knotId).getInPt();
Pt p = startPt;
do {
if (p instanceof XPt) return (XPt) p;
p = p.getNextPt();
} while (p != startPt);
return (XPt) null;
}
public void setAlt() {
boolean[] marked = getMarked();
for (int i = 0; i < nKnots; i++) {
if (!marked[i]) detAlt(findXPt(i), marked);
}
}
public void setAlt(XPt p) {
boolean[] marked = getMarked();
detAlt(p, marked);
}
public int[] getMinMaxXY(int knotId) {
int minX, minY, maxX, maxY;
Edge e1 = getFirstEdge(knotId);
Point p = e1.getInPt().getLocation();
minX = maxX = p.x; minY = maxY = p.y;
Edge e = e1;
do {
p = e.getInPt().getLocation();
if (p.x < minX) minX = p.x;
else if (p.x > maxX) maxX = p.x;
if (p.y < minY) minY = p.y;
else if (p.y > maxY) maxY = p.y;
e = e.getNext();
} while (e != e1);
int[] res = new int[4];
res[0] = minX; res[1] = maxX; res[2] = minY; res[3] = maxY;
return res;
}
public int[] getMinMaxXY(boolean[] knotMask) {
// at least one entry in knotMask must be true
int[] res, res1;
int i = 0;
while (!knotMask[i]) i++;
res = getMinMaxXY(i);
while (++i < knotMask.length) {
if (!knotMask[i]) continue;
res1 = getMinMaxXY(i);
if (res1[0] > res[0]) res[0] = res1[0];
if (res1[1] > res[1]) res[1] = res1[1];
if (res1[2] > res[2]) res[2] = res1[2];
if (res1[3] > res[3]) res[3] = res1[3];
}
return res;
}
public int[] getMinMaxXY() {
boolean[] knotMask = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) knotMask[i] = true;
return getMinMaxXY(knotMask);
}
public boolean[] getKnotMask(int[] knotIds) {
boolean[] knotMask = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) knotMask[i] = false;
for (int i = 0; i < knotIds.length; i++) knotMask[knotIds[i]] = true;
return knotMask;
}
public void rotate(int[] knotIds, int degCcw) {
// rotate the knots indicated in the knotIds array, plus
// all knots that these cross directly or indirectly,
// through an angle of degCcw (degrees counterclockwise).
// The center of rotation is the centroid of the rectangle
// spanned by the rotated knots.
int[] minMaxXY = getMinMaxXY(getKnotMask(knotIds));
int midX = (int) Math.round((minMaxXY[0]+minMaxXY[1])/2.0);
int midY = (int) Math.round((minMaxXY[2]+minMaxXY[3])/2.0);
double radCcw = (degCcw * Math.PI) / 180.0;
double cos = Math.cos(radCcw);
double sin = Math.sin(radCcw);
for (int i = 0; i < knotIds.length; i++) {
Edge e1 = getFirstEdge(knotIds[i]);
Edge e = e1;
do {
Pt p = e.getInPt();
p.rotate(midX, midY, sin, cos);
e = e.getNext();
} while (e != e1);
}
}
public void rotate(int knotId, int degCcw) {
// rotate the knot with the specified knotId, plus
// all knots that it crosses directly or indirectly,
// through an angle of degCcw (degrees counterclockwise).
// The center of the rotation is the centroid of the rectangle
// spanned by the rotated knots.
int[] knotIds = { knotId };
rotate(knotIds, degCcw);
}
void dfs(int v, boolean[][] adj, boolean[] marked) {
// depth-first search: v represents a knot
marked[v] = true;
for (int i = 0; i < marked.length; i++)
if (adj[v][i] && !marked[i]) dfs(i, adj, marked);
}
public boolean isSplit() {
boolean[][] adj = new boolean[nKnots][nKnots];
for (int i = 0; i < nKnots; i++)
for (int j = 0; j < nKnots; j++)
adj[i][j] = false;
for (int i = 0; i < nKnots; i++) {
if (nXPt[i] == 0) return true;
XPt p = firstXPt[i];
boolean firstIsOver = (p instanceof XOPt);
boolean differ = false;
XPt p1 = p;
do {
int j = p.getMate().getKnotId();
if (i != j) {
System.out.println("adj: " + i + " " + j);
adj[i][j] =adj[j][i] = true;
}
p = p.getNext();
if (firstIsOver != (p instanceof XOPt)) differ = true;
} while (p != p1);
if (!differ) return true;
}
boolean[] marked = new boolean[nKnots];
for (int i = 0; i < nKnots; i++) marked[i] = false;
dfs(0, adj, marked);
for (int i = 0; i < nKnots; i++)
if (!marked[i]) return true;
return false;
}
public void numberStrands() {
// only called if isSplit is true
nStrands = 0;
for (int i = 0; i < nKnots; i++) {
XPt p = firstXPt[i];
while (!(p instanceof XUPt)) p = p.getNext();
for (int j = 0; j < nXPt[i]; j++) {
p.getOutEdge().setStrandId(nStrands);
p = p.getNext();
p.getInEdge().setStrandId(nStrands);
if (p instanceof XUPt) nStrands++;
}
}
}
public void numberCrossings() {
int n = 0;
for (int i = 0; i < nKnots; i++) {
XPt p = firstXPt[i];
for (int j = 0; j < nXPt[i]; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
((XOPt) p).crossingId = n++;
}
}
}
public int[][] makeChecks() {
int[] nChecks = new int[nStrands];
for (int i = 0; i < nStrands; i++) nChecks[i] = 0;
for (int i = 0; i < nKnots; i++) {
if (nXPt[i] == 0) continue;
XPt p = firstXPt[i];
for (int j = 0; j < nXPt[i]; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
int maxStrand = p.getInEdge().getStrandId();
XPt pm = p.getMate(); // must be an XUPt
maxStrand = Math.max(maxStrand, pm.getInEdge().getStrandId());
maxStrand = Math.max(maxStrand, pm.getOutEdge().getStrandId());
}
}
int[][] checks = new int[nStrands][];
for (int i = 0; i < nStrands; i++) {
checks[i] = new int[2*nChecks[i]];
nChecks[i] = 0;
}
for (int i = 0; i < nKnots; i++) {
if (nXPt[i] == 0) continue;
XPt p = firstXPt[i];
for (int j = 0; j < nXPt[i]; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
int[] strands = new int[3];
strands[0] = p.getInEdge().getStrandId();
XPt pm = p.getMate();
strands[1] = pm.getInEdge().getStrandId();
strands[2] = pm.getOutEdge().getStrandId();
// sort the strands, just enough to have max last
// that is, only one pass of bubblesort is done
for (int k = 0; k < 2; k++)
if (strands[k] > strands[k+1]) {
int temp = strands[k];
strands[k] = strands[k+1];
strands[k+1] = temp;
}
int maxStrand = strands[2];
int jj = 2*nChecks[maxStrand]++;
checks[maxStrand][jj+1] = strands[i];
}
}
for (int i = 0; i < checks.length; i++) {
System.out.print("strand " + i + ":");
for (int j = 0; j < checks.length; j++)
System.out.print(" " + checks[i][j]);
System.out.println();
}
return checks;
}
boolean colorOk(int[] colors, int s, int c, int[][] checks) {
// assign color c to strand s
int i = 0;
colors[s] = c;
while (i < checks.length) {
int other0 = colors[checks[s][i]];
int other1 = colors[checks[s][i+1]];
if (other0 == other1 && c != other0) return false;
if (other0 != other1 && (c == other0 || c == other1)) return false;
i += 2;
}
if (s == nStrands-1) { // color assignment complete
// look for 2 different colors
for (int j = 1; j < colors.length; j++)
if (colors[j] != colors[0]) return true;
return false;
}
for (int j = 0; j < 3; j++)
if (colorOk(colors, j+1, s, checks)) return true;
return false;
}
public boolean tricolorable() {
numberStrands();
int[][] checks = makeChecks();
tricoloring = new int[nStrands];
tricoloring[0] = 0;
return colorOk(tricoloring, 1, 0, checks)
|| colorOk(tricoloring, 1, 1, checks);
}
void setFourEdges(XPt p, int[] edgeKind, double[] edgeAngle) {
// p must be an XOPt
XPt pm = p.getMate();
edgeKind[0] = OVER_IN;
edgeAngle[0] = p.getInEdge().getReverseAngle();
edgeKind[1] = OVER_OUT;
edgeAngle[1] = p.getOutEdge().getAngle();
edgeKind[2] = UNDER_IN;
edgeAngle[2] = pm.getInEdge().getReverseAngle();
edgeKind[3] = UNDER_OUT;
edgeAngle[3] = pm.getInEdge().getAngle();
}
void sortFourEdges(int[] edgeKind, double[] edgeAngle) {
for (int ii = 3; ii > 0; ii--)
for (int jj = 0; jj < ii; jj++)
if (edgeAngle[jj] > edgeAngle[jj+1]) {
double tempAngle = edgeAngle[jj];
edgeAngle[jj] = edgeAngle[jj+1];
edgeAngle[jj+1] = tempAngle;
int tempKind = edgeKind[jj];
edgeKind[jj] = edgeKind[jj+1];
edgeKind[jj+1] = tempKind;
}
}
int[][] getCodedMatx() throws Exception {
if (isSplit()) throw new Exception("splittable – Alex poly is zero");
numberStrands();
if (nStrands != totalCrossings)
throw new Exception("#strands = " + nStrands + " #crossings = " +
totalCrossings);
int[][] codedMatx = new int[totalCrossings][3];
// for each i, codedMatx[i][0] = col. index of 1-t entry
// codedMatx[i][1] = col. index of -1 entry
// codedMatx[i][2] = col. index of t entry
int crossingId = 0;
int[] edgeKind = new int[5];
double[] edgeAngle = new double[4];
for (int j = 0; j < nKnots; j++) {
XPt p = firstXPt[j];
for (int k = 0; k < nXPt[j]; k++, p = p.getNext()) {
if (p instanceof XUPt) continue;
XPt pm = p.getMate();
setFourEdges(p, edgeKind, edgeAngle);
sortFourEdges(edgeKind, edgeAngle);
edgeKind[4] = edgeKind[0]; // to handle circularity
int overOut = 0;
while (edgeKind[overOut] != OVER_OUT) overOut++;
codedMatx[crossingId][0] = p.getOutEdge().getStrandId();
int underInIndex = 1;
if (edgeKind[overOut+1] != UNDER_OUT) underInIndex = 2;
codedMatx[crossingId][underInIndex] = pm.getInEdge().getStrandId();
codedMatx[crossingId][3-underInIndex] = pm.getOutEdge().getStrandId();
crossingId++;
}
}
return codedMatx;
}
public int[] alex() throws Exception {
int[][] codedMatx = getCodedMatx();
double[] polyDouble = NumAnal.newtonInterp(codedMatx);
int[] polyInt = new int[nStrands];
for (int j = 0; j < nStrands; j++)
polyInt[j] = (int) Math.round(polyDouble[j]);
return polyInt;
}
public void writeLine(BufferedWriter bw, String s) {
try {
bw.write(s, 0, s.length());
bw.newLine();
}
catch (Exception anyExc) {
}
}
public void saveAlex(BufferedWriter bw) throws Exception {
int[][] codedMatx = getCodedMatx();
int n = codedMatx.length;
writeLine(bw, "> with linalg,det;");
writeLine(bw, "> A=array([seq(0,ii=1.." + (n-1)
+ ")],jj=1.." + (n-1) + ")]);" );
for (int j = 0; j < n-1; j++) {
if (codedMatx[j][0] < n-1)
writeLine(bw, "> A[" + (j+1) + "," +
(codedMatx[j][0]+1) + "]:=1-t;" );
if (codedMatx[j][1] < n-1)
writeLine(bw, "> A[" + (j+1) + "," +
(codedMatx[j][1]+1) + "]:=-1" );
if (codedMatx[j][2] < n-1)
writeLine(bw, "> A[" + (j+1) + "," +
(codedMatx[j][2]+1) + "]:=t" );
}
writeLine(bw, "> det(A);");
}
public XOPt findXOPt(Point p) {
int squaredRadius = radius*radius;
for (int j = 0; j < nKnots; j++) {
if (nXPt[j] == 0) continue;
XPt xp = firstXPt[j];
for (int k = 0; k < nXPt[j]; k++, xp = xp.getNext()) {
if (xp instanceof XUPt) continue;
Point xpLoc = xp.getLocation();
if ((xpLoc.x - p.x)*(xpLoc.x - p.x) + (xpLoc.y - p.y)*(xpLoc.y - p.y)
>= squaredRadius) continue;
return (XOPt) xp;
}
}
return (XOPt) null;
}
XOPt findFirstXOPt() {
for (int j = 0; j < nKnots; j++) {
if (nXPt[j] == 0) continue;
XPt xp = firstXPt[j];
for (int k = 0; k < nXPt[j]; k++, xp = xp.getNext()) {
if (xp instanceof XUPt) continue;
return (XOPt) xp;
}
}
return (XOPt) null;
}
void standardizeEdges(int[] edgeKind, double[] edgeAngle) {
// sort and rotate the arrays so that in counterclockwise
// order, we have out0, out1, in0, in1 as follows
// out1 - -ïƒ out0
// \ /
// \ /
// \/
// /\
// / \
// / \
// in0 >------- \ ----ïƒ in1
sortFourEdges(edgeKind, edgeAngle);
while (! (edgeKind[0] == OVER_OUT && edgeKind[1] == UNDER_OUT
|| edgeKind[0] == UNDER_OUT && edgeKind[1] == OVER_OUT ) ) {
Util.leftRotate1(edgeKind, 4); // 4 is size, not amount of rotation
Util.leftRotate1(edgeAngle, 4);
}
}
boolean isRightHanded(XOPt p) {
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
return (edgeKind[0] == OVER_OUT);
}
void setKnotId(Edge e, int knotId) {
Edge e1 = e;
do {
e.setKnotId(knotId);
e.getInPt().setKnotId(knotId);
e.getOutPt().setKnotId(knotId);
e = e.getNext();
} while (e != e1);
}
void setParentLink(Edge e, Link link) {
Edge e1 = e;
do {
e.setParentLink(link);
e.getInPt().setParentLink(link);
e.getOutPt().setParentLink(link);
e = e.getNext();
} while (e != e1);
}
public void joinVertical(XOPt p) {
if (!isRightHanded(p)) {
p.toggle();
wrapUp();
joinHorizontal(p);
}
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge(); out1 = pm.getOutEdge();
in0 = p.getInEdge(); in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
joinEdges(in0, out1);
joinEdges(in1, out0);
if (overKnotId == underKnotId) { // a knot splits into two
int newKnotId = nKnots++;
firstEdge[overKnotId] = out1;
firstEdge[newKnotId] = out0;
setKnotId(in1, newKnotId);
}
else { // two knots become one
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp();
}
public void joinHorizontal(XOPt p) {
if (!isRightHanded(p)) {
p.toggle();
wrapUp();
joinVertical(p);
return;
}
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge();
out1 = pm.getOutEdge();
in0 = p.getInEdge();
in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
NXPt elbow0 = new NXPt(p);
NXPt elbow1 = new NXPt(p);
out0.setInPt(elbow0); out1.setInPt(elbow0);
in0.setOutPt(elbow1); in1.setOutPt(elbow1);
in0.setNext(in1); in1.setNext(in0);
out0.setPrev(out1); out1.setPrev(out0);
elbow0.setInEdge(out1); elbow0.setOutEdge(out0);
elbow1.setInEdge(in1); elbow1.setOutEdge(in0);
if (overKnotId == underKnotId) { // a knot stays one knot
elbow1.setInEdge(in1); elbow1.setOutEdge(in0);
Edge.reverseEdges(out1, in0);
joinEdges(out1, out0);
joinEdges(in1, in0);
}
else { // two knots become one
elbow1.setInEdge(in0); elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
joinEdges(out1, out0);
joinEdges(in0, in1);
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp();
}
public void bktJoinVertical(XOPt p) {
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge(); out1 = pm.getOutEdge();
in0 = p.getInEdge(); in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
NXPt elbow0 = new NXPt(p);
NXPt elbow1 = new NXPt(p);
in0.setOutPt(elbow0); out1.setInPt(elbow0);
in1.setOutPt(elbow1); out0.setInPt(elbow1);
in0.setNext(in1); in1.setNext(in0);
out0.setPrev(out1); out1.setPrev(out0);
elbow0.setInEdge(out1); elbow0.setOutEdge(out0);
elbow1.setInEdge(in1); elbow1.setOutEdge(in0);
if (overKnotId == underKnotId) { // a knot stays one knot
elbow1.setInEdge(in0); elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
}
else { // two knots become one
elbow1.setInEdge(in0); elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp();
}
public void bktJoinHorizontal(XOPt p) {
XUPt pm = (XUPt) p.getMate();
double[] edgeAngle = new double[4];
int[] edgeKind = new int[4];
setFourEdges(p, edgeKind, edgeAngle);
standardizeEdges(edgeKind, edgeAngle);
Edge out0 = null, out1 = null, in0 = null, in1 = null;
if (edgeKind[0] == OVER_OUT) {
out0 = p.getOutEdge(); out1 = pm.getOutEdge();
in0 = p.getInEdge(); in1 = pm.getInEdge();
}
else {
out0 = pm.getOutEdge(); out1 = p.getOutEdge();
in0 = pm.getInEdge(); in1 = p.getInEdge();
}
int overKnotId = p.getKnotId();
int underKnotId = pm.getKnotId();
NXPt elbow0 = new NXPt(p);
NXPt elbow1 = new NXPt(p);
out0.setInPt(elbow0); out1.setInPt(elbow0);
in0.setOutPt(elbow1); in1.setOutPt(elbow1);
in0.setNext(in1); in1.setNext(in0);
out0.setPrev(out1); out1.setPrev(out0);
if (overKnotId == underKnotId) { // a knot stays one knot
elbow1.setInEdge(in1);
elbow1.setOutEdge(in0);
Edge.reverseEdges(out1, in0);
}
else { // two knots become one
elbow1.setInEdge(in0);
elbow1.setOutEdge(in1);
Edge.reverseEdges(out1, in1);
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(in0, retainedKnotId);
if (freedKnotId == nKnots - 1) {
firstEdge[freedKnotId] = firstEdge[nKnots - 1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp(false);
}
NXPt cutPoint(Pt a, Pt b) {
// a point between a and b, backed up a distance of
// CUT_DELTA from b. If this is too large, use midpt of
// a and b instead.
Point ap = a.getLocation();
Point bp = b.getLocation();
int dx = b.x - a.x;
int dy = b.y - a.y;
double length = Math.sqrt((double) (dx*dx + dy*dy));
if (length < 2*CUT_DELTA)
return new NXPt((a.x+b.x)/2, (a.y+b.y)/2, this, 0);
int x = (int) (bp.x - dx*CUT_DELTA/length);
int y = (int) (bp.y - dy*CUT_DELTA/length);
return new NXPt(x, y, this, 0);
}
void joinEdges(Edge in, Edge out) {
NXPt interm1 = cutPoint(in.getInPt(), in.getOutPt());
NXPt interm2 = cutPoint(out.getOutPt(), out.getInPt());
Edge bridge = new Edge(interm1, interm2, this, 0);
in.setOutPt(interm1);
out.setInPt(interm2);
interm1.setInEdge(in); interm1.setOutEdge(bridge);
interm2.setInEdge(bridge); interm2.setOutEdge(out);
in.setNext(bridge); bridge.setNext(out);
out.setPrev(bridge); bridge.setPrev(in);
}
public void nullify(XOPt pOver) {
XUPt pUnder = (XUPt) pOver.getMate();
int overKnotId = pOver.getKnotId();
int underKnotId = pUnder.getKnotId();
Edge overIn = pOver.getInEdge();
Edge underIn = pUnder.getInEdge();
Edge overOut = pOver.getOutEdge();
Edge underOut = pUnder.getOutEdge();
joinEdges(underIn, overOut);
joinEdges(overIn, underOut);
if (underKnotId == overKnotId) { // a knot splits into two
int newKnotId = nKnots++;
firstEdge[overKnotId] = overOut;
firstEdge[underKnotId] = underOut;
setKnotId(overOut, newKnotId);
setKnotId(underOut, newKnotId);
}
else { // two knots become one
int retainedKnotId = Math.min(overKnotId, underKnotId);
int freedKnotId = Math.max(overKnotId, underKnotId);
setKnotId(underIn, retainedKnotId);
if (freedKnotId != nKnots-1) {
firstEdge[freedKnotId] = firstEdge[nKnots-1];
setKnotId(firstEdge[freedKnotId], freedKnotId);
}
nKnots--;
}
wrapUp(false);
}
int findSplitUnknot() {
for (int ii = 0; ii < nKnots; ii++)
if (nXPt[ii] == 0) return ii;
return -1;
}
void deleteSplitUnknot(int knotId) {
int oldLast = --nKnots;
if (knotId == oldLast) return;
if (firstEdge[oldLast] == null) {
firstEdge[knotId] = null;
nXPt[knotId] = 0;
firstXPt[knotId] = null;
return;
}
firstEdge[knotId] = firstEdge[oldLast];
nXPt[knotId] = nXPt[oldLast];
firstXPt[knotId] = firstXPt[oldLast];
setKnotId(firstEdge[oldLast], knotId);
}
void deleteConsecXPts(XPt p, XPt q) {
// link must be skeletonized.
// p must be predecessor of q in list of XPts for the knot
// p and q must form a Type I or Type II configuration
// this function only deletes p and q, not their mates
// in case of a Type II configuration
int knotId = p.getKnotId();
if (nXPt[knotId] == 2) {
// no more XPts left in knot
nXPt[knotId] = 0;
firstEdge[knotId] = null;
firstXPt[knotId] = null;
return;
}
NXPt pNew = new NXPt(p), qNew = new NXPt(q);
p.getInEdge().setOutPt(pNew); p.getOutEdge().setInPt(pNew);
q.getInEdge().setOutPt(qNew); q.getOutEdge().setInPt(qNew);
XPt pPrev = p.getPrev();
XPt qNext = q.getNext();
pPrev.setNext(qNext); qNext.setPrev(pPrev);
Edge e1 = pPrev.getOutEdge();
Edge e2 = qNext.getInEdge();
e1.setNext(e2); e2.setPrev(e1);
nXPt[knotId] -= 2;
firstEdge[knotId] = e2;
firstXPt[knotId] = qNext;
}
public void simplifyIAndII() {
// link must be skeletonized
// look for and remove all Types I and II configurations
// note that removing such configurations might lead to more
// such configurations to be removed (the more the better)
int n = nKnots;
// n is decremented each time we go through a knot with no change
// when a knot is changed, n is reset to nKnots
// outer loop stops only when n is 0, i.e. we hav gone
// thru all the knots with no change in any
int knotId = 0;
for ( ; n > 0; knotId = (knotId+1) % nKnots) {
boolean knotChanged = false;
int m = nXPt[knotId];
// m controls the inner loop in a manner similar to
// how n controls the outer loop
if (m == 0) {
n--; continue;
}
XPt p = firstXPt[knotId];
while (m > 0) {
XPt pm = p.getMate();
XPt q = p.getNext(), qm = q.getMate();
if (q == pm) { // Type I
deleteConsecXPts(p, q);
m = nXPt[knotId]; // hav to go through all remaining XPts
p = firstXPt[knotId];
knotChanged = true;
continue;
}
if ( (p instanceof XOPt) == (q instanceof XOPt) &&
(pm.getNext() == qm || pm.getPrev() == qm) ) { // Type II
deleteConsecXPts(p, q);
if (pm.getNext() == qm) deleteConsecXPts(pm, qm);
else deleteConsecXPts(qm, pm);
m = nXPt[knotId];
knotChanged = true;
continue;
}
m--; p = q;
}
if (knotChanged) n = nKnots;
else n--;
}
}
public static LPoly bktPoly(Link x) {
int splitUnknot = x.findSplitUnknot();
if (splitUnknot >= 0) {
if (x.nKnots == 1) return LPoly.ONE;
else {
x.deleteSplitUnknot(splitUnknot);
return LPoly.NEG_A2A_2.mul(bktPoly(x));
}
}
Link x1 = new Link(x);
XOPt xp = x1.findFirstXOPt();
boolean rightHanded = x1.isRightHanded(xp);
x1.bktJoinVertical(xp);
Link x2 = new Link(x);
x2.bktJoinVertical(xp);
LPoly p1 = bktPoly(x1);
LPoly p2 = bktPoly(x2);
if (rightHanded) return
LPoly.A.mul(p1).add(LPoly.A_1.mul(p2));
else return
LPoly.A.mul(p2).add(LPoly.A_1.mul(p1));
}
public int writhe() {
int res = 0;
for (int ii = 0; ii < nKnots; ii++) {
if (nXPt[ii] == 0) continue;
XPt p = firstXPt[ii];
int n = nXPt[ii];
for (int j = 0; j < n; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
if (isRightHanded( (XOPt) p ) ) res++;
else res--;
}
}
return res;
}
public int selfWrithe() {
int res = 0;
for (int ii = 0; ii < nKnots; ii++) {
if (nXPt[ii] == 0) continue;
XPt p = firstXPt[ii];
int n = nXPt[ii];
for (int j = 0; j < n; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
if (p.getKnotId() != p.getMate().getKnotId()) continue;
if (isRightHanded( (XOPt) p ) ) res++;
else res--;
}
}
return res;
}
public int linkingNumber() {
int res = 0;
for (int ii = 0; ii < nKnots; ii++) {
if (nXPt[ii] == 0) continue;
XPt p = firstXPt[ii];
int n = nXPt[ii];
for (int j = 0; j < n; j++, p = p.getNext()) {
if (p instanceof XUPt) continue;
if (p.getKnotId() == p.getMate().getKnotId()) continue;
if (isRightHanded( (XOPt) p ) ) res++;
else res--;
}
}
return res/2;
}
public static LPoly fBktPoly(Link x) {
// hopefully a faster version
Link simplifiedCopy = new Link(x);
simplifiedCopy.simplifyIAndII();
x.computeTotalCrossings();
simplifiedCopy.computeTotalCrossings();
if (simplifiedCopy.totalCrossings < x.totalCrossings) {
int w0 = x.writhe();
int w1 = simplifiedCopy.writhe();
LPoly factor = new LPoly( new Term (
( (w0-w1)%2 == 0) ? 1 : -1, 3*(w0-w1) ) );
return factor.mul(fBktPoly(simplifiedCopy));
}
int splitUnknot = x.findSplitUnknot();
if (splitUnknot >= 0) {
if (x.nKnots == 1) return LPoly.ONE;
else {
x.deleteSplitUnknot(splitUnknot);
return LPoly.NEG_A2A_2.mul(bktPoly(x));
}
}
Link x1 = new Link(x);
XOPt xp = x1.findFirstXOPt();
boolean rightHanded = x1.isRightHanded(xp);
x1.bktJoinVertical(xp);
Link x2 = new Link(x);
xp = x2.findFirstXOPt();
x2.bktJoinHorizontal(xp);
LPoly p1 = bktPoly(x1);
LPoly p2 = bktPoly(x2);
if (rightHanded) return
LPoly.A.mul(p1).add(LPoly.A_1.mul(p2));
else return
LPoly.A.mul(p2).add(LPoly.A_1.mul(p1));
}
public void print() {
for (int knotId = 0; knotId < nKnots; knotId++) {
System.out.println("knot #" + knotId + ":");
if (firstEdge[knotId] == null) {
System.out.println("empty knot");
continue;
}
Edge e = firstEdge[knotId];
do {
e.print();
e = e.getNext();
} while (e != firstEdge[knotId]);
}
}
public void draw(Graphics g, int nKnotsToDraw, boolean ignoreCrossing) {
// System.out.println("in Link.draw link to draw:");
// print();
// System.out.println("end of link to draw");
for (int knotId = 0; knotId < nKnotsToDraw; knotId++) {
// System.out.println("knot#" + knotId + ":");
Edge knotFirstEdge = firstEdge[knotId];
if (knotFirstEdge == null) continue;
Edge e = knotFirstEdge;
Color edgeColor = edgeColors[knotId % edgeColors.length];
for (int i = 0; i < nKnotEdges[knotId]; i++) {
// System.out.println(e.toString());
e.draw(g, edgeColor, ignoreCrossing, marked[knotId]);
e = e.getNext();
}
firstEdge[knotId].drawArrow(g, edgeColor, ignoreCrossing, false);
}
}
public void draw(Graphics g, boolean ignoreCrossing) {
draw(g, nKnots, ignoreCrossing);
}
public void xorDraw(Graphics g, int startKnotId, boolean ignoreCrossing) {
Color edgeColor = Color.green;
for (int knotId = startKnotId; knotId < nKnots; knotId++) {
Edge knotFirstEdge = firstEdge[knotId];
if (knotFirstEdge == null) continue;
Edge e = knotFirstEdge;
do {
e.xorDraw(g, edgeColor, ignoreCrossing);
e = e.getNext();
} while (e != knotFirstEdge);
}
}
public void erase(Graphics g, Color c, boolean ignoreCrossing) {
for (int knotId = 0; knotId < nKnots; knotId--) {
Edge knotFirstEdge = firstEdge[knotId];
if (knotFirstEdge == null) continue;
Edge e = knotFirstEdge;
do {
e.draw(g, c, ignoreCrossing, !marked[knotId]);
e = e.getNext();
} while (e != knotFirstEdge);
}
}
public void tricolorDraw(Graphics g) {
for (int knotId = 0; knotId < nKnots; knotId++) {
if (nXPt[knotId] == 0) continue;
XPt p = firstXPt[knotId];
XPt pu = null;
for (int j = 0; j < nXPt[knotId]; j++) {
if (p instanceof XUPt) {
pu = p; break;
}
p = p.getNext();
}
if (pu == null) continue;
Edge knotFirstEdge = firstEdge[knotId];
Edge e = knotFirstEdge;
int colorIndex = 0;
do {
if (e.getInPt() instanceof XUPt)
colorIndex = tricoloring[e.getStrandId()];
e.draw(g, rgb[colorIndex], false, !marked[knotId]);
e = e.getNext();
} while (e != knotFirstEdge);
}
}
public int dupChosenKnot(Edge e) {
// duplicate knot containing edge e, returns old #knots
Link dupLink = new Link(this);
int dupKnotId = e.getKnotId();
XPt p = dupLink.firstXPt[dupKnotId];
int n = dupLink.nXPt[dupKnotId];
for (int j = 0; j < n; j++, p = p.getNext()) {
// get rid of crossings with other knots
if (p.getMate().getKnotId() == dupKnotId) continue;
NXPt p1 = new NXPt(p);
Edge e1 = p1.getInEdge();
Edge e2 = p1.getOutEdge();
p1.setInEdge(e1); p1.setOutEdge(e2);
e1.setOutPt(p1); e2.setInPt(p1);
}
int newKnotId = nKnots++;
firstEdge[newKnotId] = dupLink.firstEdge[dupKnotId];
setKnotId(firstEdge[newKnotId], newKnotId);
setParentLink(firstEdge[newKnotId], this);
absorbCollinear(newKnotId);
linkXPts(newKnotId);
return newKnotId;
}
public int addLink(Link linkToAdd) {
// add link, return old #knots
Link dupLink = new Link(linkToAdd);
int n = nKnots;
int n1 = dupLink.nKnots;
for (int j = 0; j < n1; j++) {
firstEdge[n+j] = dupLink.firstEdge[j];
setKnotId(firstEdge[n+j], n+j);
setParentLink(firstEdge[n+j], this);
linkXPts(n+j);
}
nKnots += n1;
return n;
}
public int dupLink() {
return addLink(this);
}
public void moveKnot(int knotId, int dx, int dy) {
Edge e = firstEdge[knotId];
Edge e1 = e;
do {
Pt p = e.getInPt();
Point pLoc = p.getLocation();
p.setX(pLoc.x + dx);
p.setY(pLoc.y + dy);
e = e.getNext();
} while (e != e1);
}
public void moveKnots(int startKnotId, int dx, int dy) {
for (int j = startKnotId; j < nKnots; j++)
moveKnot(j, dx, dy);
}
public void doubleY() {
for (int j = 0; j < nKnots; j++) {
Edge e = firstEdge[j];
if (e == null) continue;
Edge e1 = e;
do {
Pt p = e.getInPt();
Point pLoc = p.getLocation();
p.setY(2*pLoc.y);
e = e.getNext();
} while (e != e1);
}
}
public void hiliteCrossings(Graphics g, int radius) {
Color oldColor = g.getColor();
g.setColor(Color.blue);
for (int j = 0; j < nKnots; j++) {
if (nXPt[j] == 0) continue;
XPt p = firstXPt[j];
XPt pFirst = p;
do {
if (p instanceof XOPt) {
Point pLoc = p.getLocation();
g.drawOval(pLoc.x - radius, pLoc.y - radius, 2 * radius, 2 * radius);
}
p = p.getNext();
} while (p != pFirst);
}
g.setColor(oldColor);
}
public static String[] getKnotColorStrings() {
String[] res = new String[edgeColors.length];
for (int j = 0; j < edgeColors.length; j++) {
Color c = edgeColors[j];
res[j] = "2 setlinewidth " + c.getRed() + " "
+ c.getGreen() + " " + c.getBlue()
+ " setrgbcolor";
}
return res;
}
public static String getSelectedEdgeColorString() {
return "1 setlinewidth 0 0 1 setrgbcolor";
}
public static String[] getKnotBWStrings() {
return knotBWStrings;
}
public static String getSelectedEdgeBWString() {
return "1 setlinewidth 0 0 0 setrgbcolor";
}
public Boolean knotOutsideClipRect(int knotId, Point[] clipRect) {
// clipRect[0] = (left, top); clipRect[1] = (right, bottom)
Edge start = firstEdge[knotId];
Edge e = start;
do {
if (e.insideRect(clipRect)) return false;
e = e.getNext();
} while (e != start);
return true;
}
public Vector getUnfitPts(int leftX, int rightX, int tolerance) {
// return a Vector of all the Pt’s in the link whose
// x-distance from either leftX or rightX is less than
// tolerance
Vector res = new Vector();
for (int j = 0; j < nKnots; j++) {
Edge e = firstEdge[j];
Edge e1 = e;
do {
if (e.unfitForIterate(leftX, rightX, tolerance))
res.addElement(e.inPt);
e = e.getNext();
} while (e != e1);
}
return res;
}
public Vector getCrossedEdge(int leftX, int rightX) {
// return a Vector all Edges in the link that are
// crossed by the vertical lines x = leftX and x = rightX
Vector res = new Vector();
int left = 0, right = 0;
for (int j = 0; j < nKnots; j++) {
Edge e = firstEdge[j];
Edge e1= e;
do {
int x1 = e.inPt.x;
int x2 = e.outPt.x;
if ((x1 < leftX) == (leftX < x2) ||
(x1 < rightX) == (rightX < x2)) {
res.addElement(e);
if ((x1 < leftX) == (leftX < x2)) left++;
if ((x1 < rightX) == (rightX < x2)) right++;
}
e = e.getNext();
} while (e != e1);
}
res.addElement(new Integer(left));
res.addElement(new Integer(right));
return res;
}
}
LinkCanvas.java:
----------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkCanvas extends Canvas
implements MouseListener, MouseMotionListener,
ActionListener {
static final int BETWEEN_KNOTS = 1;
static final int VERTEX = 2;
static final int CROSSING = 3;
static final int COMPLETE = 4;
static final int STRAIGHTEN = 5;
static final int R1I = 6;
static final int R1I_CROSSING = 7;
static final int R2I = 8;
static final int R2I_CROSSING = 9;
static final int R3 = 10;
static final int MAC = 10;
static final int MAC_CROSSING = 11;
static final int UNLINK_KNOT = 12;
static final int UNLINK_CONFIRM = 13;
static final int RECT_UNKNOT = 14;
static final int ROTATE = 15;
static final int ROTATE_CONFIRM = 16;
static final int TRICOLOR = 17;
static final int SKELETON = 18;
static final int JOIN_VERTICAL = 19;
static final int JOIN_HORIZONTAL = 20;
static final int BKT_POLY = 21;
static final int SIMPLIFY = 22;
static final int DUP_KNOT_CHOOSE = 23;
static final int DUP_KNOT_MOVE = 24;
static final int REVERSE_KNOT = 25;
static final int REVERSE_CONFIRM = 26;
static final int NULLIFY = 27;
static final int EXPAND = 28;
static final int EXPAND_CROSSING = 29; // choosing a crossing for expand
static final int CLIP_RECT = 30;
static final int FIRST_EDGE = 31;
static final int MARK_KNOT = 32;
static final int MULTI_KNT = 33;
static final int MULTI_KNT_UNLINK = 34;
static final int MULTI_KNT_CONFIRM = 35;
static final int ZIGZAG = 36;
static final int ITERATE = 37;
static final int REFLECT_CONFIRM = 38;
static final int HOMFLY = 1;
static final int BRACKET = 2;
static final String[] modeNames =
{ "", "BETWEEN_KNOTS", "VERTEX", "CROSSING", "COMPLETE", "STRAIGHTEN",
"R1I", "R1I_CROSSING", "R2I", "R2I_CROSSING", "R3", "MAC",
"MAC_CROSSING", "UNLINK_KNOT", "UNLINK_CONFIRM", "RECT",
"TRICOLOR", "SKELETON", "JOIN_VERTICAL", "JOIN_HORIZONTAL",
"BKT_POLY", "SIMPLIFY", "DUP_KNOT_CHOOSE", "DUP_KNOT_MOVE",
"REVERSE_KNOT", "REVERSE_CONFIRM", "NULLIFY", "EXPAND",
"EXPAND_CROSSING",
"CLIP_RECT", "FIRST_EDGE", "MARK_KNOT", "MULTI_KNT",
"MULTI_KNT_UNLINK", "MULTI_KNT_CONFIRM", "ZIGZAG", "ITERATE",
"REFLECT_CONFIRM",
};
static final int EDGES_MODE = 1;
static final int POINTS_MODE = 2;
static final int RADIUS = 5;
static final int MIN_LENGTH = 15;
static final int INIT_LINK_EDGEMAX = 16;
static final int INIT_HISTORYMAX = 1000;
static final int MAX_CHOSEN_PTS = 100;
static final int tolerance = 5;
static final int RECT_TOLERANCE = 8;
static final double ONE_THIRD = 1.0/3.0;
static final double TWO_THIRDS = 2.0/3.0;
static final int NODES_BAR_X = 10;
static final int NODES_BAR_Y = 30;
static final int ITERATE_DX = 20;
static final int ITERATE_GAP = 20;
static final int ITERATE_HOWMANY = 20;
static final int NONE = 0, PRESENT = 1;
int arcRadius = 5;
int radius = 5;
// knots that are unlinked are retained in the link so that
// the remaining knots can retain their knot id’s and colors.
// These unlinked knots are displayed as square unknots in
// a reserved area at the top of the canvas. The constants
// below define the size, location and separation for these
// square unknots. Note that the location of each unlinked
// unknot is determined by its knot id. The other knots in
// link are not allowed to occupy the area with y <
// FORBIDDEN_Y.
public static final int ISOLATED_SIDE = 10;
public static final int ISOLATED_TOP_MARGIN = 3;
public static final int ISOLATED_BOTTOM_MARGIN = 3;
static final int FORBIDDEN_Y = ISOLATED_TOP_MARGIN +
ISOLATED_SIDE + ISOLATED_BOTTOM_MARGIN;
public static final int ISOLATED_DIST = 5;
public static final int GRID_DELTA = 10;
Frame frame;
int state = BETWEEN_KNOTS, pickMode, oldState;
boolean gridOn = true;
Link link, oldLink = null, reverseOrig;
// UnitLink iterLink = null;
int knotId;
NXPt startPt;
NXPt newPt;
NXPt lastPt;
Edge lastEdge, newEdge;
int intersectCt = 0;
double[] ta;
Edge[] ea;
XOPt[] xoa;
int[] xptx, xpty;
int knotEdgeCt = 0, linkEdgeCt = 0;
int inx, iny, outx, outy;
int linkEdgeMax = INIT_LINK_EDGEMAX;
int historyMax = INIT_HISTORYMAX;
int seriesMax = INIT_HISTORYMAX;
int nChosenEdges = 0, nChosenPoints = 0;
Edge chosenEdge1, chosenEdge2, lastClickedEdge, lastChosenEdge;
Point[] chosenPoints;
Point[] pa1 = new Point[1], pa2 = new Point[2];
Point lastPtLoc = new Point(200, 200);
boolean altFlag, reviewMode = false;
Link skeletonCopy;
Link clipboard = null;
// TreeNode root, currentNode;
double scaleFactor = 0.45;
int expandType = 0;
String currKntName = null, lastKntName = null;
String lastLoadName = null;
Image background = null;
Edge selectEdge;
Point lastClickedPoint = null, lastDupPoint = null;
Image offscreen;
int nOldKnots = 0;
Vector pts = null, edges = null;
Link[] history;
int[] seriesStart;
String[] seriesName;
int nLinks, nSeries, currentLink, currentSeries;
int rectLeft, rectTop, rectWidth, rectHeight;
int rectStage;
int clipCt, drawClipCt = 0;
Rectangle[] updateClipRegions = null;
int pageWidth = 600, pageHeight = 750;
Dialog headingDialog, scaleFactorDialog, pageSizeDialog;
TextField headingTF, scaleFactorTF, pageSizeTF;
String multiKntFilename;
int underlinePos = 0;
int degCcw = 0; // number of degrees to rotate, counterclockwise
static int boxWd = 270, boxHt = 220;
String[] translations = {
"30 540 translate", "310 540 translate",
"310 300 translate", "30 300 translate",
"30 60 translate", "310 60 translate",
};
String[] initPopupCmds = {
"draw",
// "draw w/ bg",
"load",
// "tangle", "pretzel", "braid", "torus",
// "(load tree", "homfly tree", "bracket tree", ")",
};
String[] betweenKnotsPopupCmds = {
"complete", "paste", "add load", "dup knot", "dup link", "print",
};
String[] vertexPopupCmds = {
"undo", "close |", "close _", "close", "cancel knot", // "zigzag",
"print",
};
String[] confirmPopupCmds = {
"confirm", "alternate",
};
String[] altPopupCmds = {
"confirm", "alternate",
};
String[] nonaltPopupCmds = {
"confirm", "non-alternate",
};
String[] completePopupCmds = {
"r1d", "r1i", "mac",
"(new", "draw",
// "draw w/ bg",
"load",
// "tangle", "pretzel", "braid", "torus",
")",
// "remove bg",
"(save", "save link", "save series", "save Jenkins",
"save knt", "save multi knt",
"save PS", "save PS BW", "save all Jenkins",
// "save Alex",
")",
"init", "load",
"copy", "add",
"(manipulate", "reflect",
// "flip horizontal", "flip vertical",
"unlink knot", "reverse knot", "double Y",
"toggle mark", ")",
"(rotate", "90 ccw", "180 ccw", "270 ccw", ")", "review",
"(test",
// "alex", "wirtinger",
"tricolor",
// "bkt poly", // "fbkt poly",
// "homfly", "homfly-new",
// "KL-compare",
// "Kauffman-L-new",
// "Kauffman-unoriented",
// "Kauffman-F",
// "Kauffman-F-G",
// "simplify", "skeleton", "nullify", "||", "=",
")", "grid toggle",
"first edge",
// "(tree expand", "homfly", "bracket", ")",
// "(load tree", "homfly tree", "bracket tree", ")",
"exit",
};
String[] expandPopupCmds = {
"r1d", "r1i", "mac",
// "expand", "cut",
// "up", "down", "sibling", "next",
// "(navigate", "forward", "backward", "first", "last", ")",
// "heading", "save tree", "save tree PS",
// "scale", "page size", "irst page", "toggle mark", "report", "quit",
};
String[] donePopupCmds = {
"done",
};
String[] cancelPopupCmds = {
"cancel",
};
String[] confirmCancelPopupCmds = {
"confirm", "cancel",
};
String[] pickPopupCmds = {
// "clip",
"points", "undo", "edges", "complete", "complete |",
"complete –", "cancel",
};
String[] reviewPopupCmds = {
"copy", "resume", "copy/resume",
"(save", "save knt",
"save PS", "save PS BW",
"save Jenkins", "save all Jenkins",
// "save Alex",
")",
"prev series", "next series", "first series", "last series",
};
String[] multiKntPopupCmds = {
"continue", "done multi",
};
// String[] iteratePopupCmds = {
// "make knots", "make matrix",
// "cancel",
// };
PopupMenu initPopupMenu, betweenKnotsPopupMenu, vertexPopupMenu,
confirmPopupMenu, quitPopupMenu, completeKnotPopupMenu,
completePopupMenu, pickPopupMenu, reviewPopupMenu,
altPopupMenu, nonaltPopupMenu, cancelPopupMenu,
confirmCancelPopupMenu, expandPopupMenu, donePopupMenu,
multiKntPopupMenu, iteratePopupMenu;
PopupMenu currentPopupMenu = null, oldPopupMenu = null;
Dimension preferredSize;
Label infoLabel, statusLabel;
boolean initializing = true;
LinkCanvas(Frame f, Dimension prefSize, Label infoLabel, Label statusLabel) {
// LPoly2.init();
frame = f;
preferredSize = prefSize;
this.infoLabel = infoLabel;
this.statusLabel = statusLabel;
setBackground(Color.white);
addMouseListener(this);
addMouseMotionListener(this);
chosenPoints = new Point[MAX_CHOSEN_PTS];
initPopupMenu = MakePopupMenu.make(initPopupCmds, this);
betweenKnotsPopupMenu = MakePopupMenu.make(betweenKnotsPopupCmds, this);
vertexPopupMenu = MakePopupMenu.make(vertexPopupCmds, this);
confirmPopupMenu = MakePopupMenu.make(confirmPopupCmds, this);
altPopupMenu = MakePopupMenu.make(altPopupCmds, this);
nonaltPopupMenu = MakePopupMenu.make(nonaltPopupCmds, this);
completePopupMenu = MakePopupMenu.make(completePopupCmds, this);
pickPopupMenu = MakePopupMenu.make(pickPopupCmds, this);
reviewPopupMenu = MakePopupMenu.make(reviewPopupCmds, this);
confirmCancelPopupMenu = MakePopupMenu.make(confirmCancelPopupCmds, this);
cancelPopupMenu = MakePopupMenu.make(cancelPopupCmds, this);
confirmPopupMenu = MakePopupMenu.make(confirmPopupCmds, this);
expandPopupMenu = MakePopupMenu.make(expandPopupCmds, this);
donePopupMenu = MakePopupMenu.make(donePopupCmds, this);
multiKntPopupMenu = MakePopupMenu.make(multiKntPopupCmds, this);
// iteratePopupMenu = MakePopupMenu.make(iteratePopupCmds, this);
completeKnotPopupMenu = completePopupMenu;
history= new Link[historyMax];
seriesStart = new int[seriesMax];
seriesName = new String[seriesMax];
createArrays();
nLinks = 0;
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
setPopupMenu(initPopupMenu);
// makeOffscreen();
// updateDiagram();
// initPopupMenu.show(this, 200, 200);
}
public void setArcRadius(int r) {
arcRadius = r;
}
public void showInitPopupMedu() {
initPopupMenu.show(this, 200, 200);
}
void setPopupMenu(PopupMenu pm) {
if (pm == null) {
System.out.println("setPopupMenu: null pm state = " + state);
return;
}
if (currentPopupMenu == pm) return;
if (currentPopupMenu != pm) remove(currentPopupMenu);
add(currentPopupMenu = pm);
}
protected void processMouseEvent(MouseEvent e) {
if (e.isPopupTrigger() && currentPopupMenu != null)
currentPopupMenu.show(e.getComponent(), e.getX(), e.getY());
super.processMouseEvent( e );
}
void review() {
setPopupMenu(reviewPopupMenu);
statusLabel.setText("Review");
currentLink = nLinks-1;
currentSeries = nSeries-1;
}
void resume() {
setPopupMenu(completePopupMenu);
statusLabel.setText("Link complete");
link = history[nLinks-1];
currentSeries = nSeries - 1;
currentLink = nLinks - 1;
reviewMode = false;
updateInfoAndDiagram();
}
void copyResume() {
addSeries();
addHistory(new Link(history[currentLink]));
history[nLinks-1].clearSelectedEdges();
resume();
}
void copy() {
clipboard = new Link(link);
}
void paste(Link pastedLink) {
makeOffscreen();
lastDupPoint = null;
nOldKnots = link.addLink(pastedLink);
Graphics g = offscreen.getGraphics();
link.xorDraw(g, nOldKnots, true);
state = DUP_KNOT_MOVE;
updateInfoAndDiagram();
statusLabel.setText("drag to move added link");
}
void paste() {
if (clipboard == null) {
statusLabel.setText("no link in clipboard");
return;
}
paste(clipboard);
}
void prevLink() {
if (currentLink == 0) return;
link = history[--currentLink];
if (currentSeries > 0 && currentLink < seriesStart[currentSeries])
currentSeries--;
updateInfoAndDiagram();
}
void nextLink() {
if (currentLink >= nLinks-1) return;
link = history[++currentLink];
if (currentSeries < nSeries-1 &&
currentLink == seriesStart[currentSeries+1])
currentSeries++;
updateInfoAndDiagram();
}
void firstLink() {
currentLink = 0;
currentSeries = 0;
link = history[currentLink];
updateInfoAndDiagram();
}
void lastLink() {
currentLink = nLinks-1;
currentSeries = nSeries-1;
link = history[currentLink];
updateInfoAndDiagram();
}
void prevSeries() {
if (currentSeries == 0) return;
currentLink = seriesStart[--currentSeries];
link = history[currentLink];
updateInfoAndDiagram();
}
void nextSeries() {
if (currentSeries >= nSeries-1) return;
currentLink = seriesStart[++currentSeries];
link = history[currentLink];
updateInfoAndDiagram();
}
void firstSeries() {
firstLink();
}
void lastSeries() {
currentSeries = nSeries-1;
currentLink = seriesStart[currentSeries];
link = history[currentLink];
updateInfoAndDiagram();
}
public void actionPerformed(ActionEvent e) {
System.out.println("in actionPerformed");
if (e.getSource() instanceof TextField) {
TextField tf = (TextField) e.getSource();
String s = tf.getText();
if (tf == headingTF) {
// currentNode.setHeading(s);
headingDialog.dispose();
return;
}
else if (tf == scaleFactorTF) {
scaleFactor = Double.valueOf(s).doubleValue();
scaleFactorDialog.dispose();
return;
}
else if (tf == pageSizeTF) {
int blankPos = s.indexOf(" ");
if (blankPos < 0) return;
int w = Integer.parseInt(s.substring(0, blankPos));
int h = Integer.parseInt(s.substring(blankPos+1));
pageWidth = w; pageHeight = h;
pageSizeDialog.dispose();
return;
}
}
String cmd = e.getActionCommand();
System.out.println("cmd = " + cmd);
if (cmd.equals("exit")) exitPressed();
else if (cmd.equals("complete")) completePressed();
else if (cmd.equals("complete |")) completeVert();
else if (cmd.equals("complete _")) completeHoriz();
else if (cmd.equals("cancel")) cancelPressed();
else if (cmd.equals("cancel knot")) cancelKnot();
else if (cmd.equals("cancel rect")) cancelKnot();
else if (cmd.equals("confirm")) confirmPressed();
else if (cmd.equals("alternate")) alternate();
else if (cmd.equals("non-alternate")) nonAlternate();
else if (cmd.equals("reflect")) reflect();
// else if (cmd.equals("flip vertical")) flipVertical();
// else if (cmd.equals("flip horizontal")) flipHorizontal();
else if (cmd.equals("unlink knot")) unlinkKnot();
else if (cmd.equals("reverse knot")) reverseKnot();
else if (cmd.equals("print")) printLink();
else if (cmd.equals("close")) closeKnot();
else if (cmd.equals("close |")) closeVert();
else if (cmd.equals("close _")) closeHoriz();
else if (cmd.equals("edges")) edges();
else if (cmd.equals("points")) points();
else if (cmd.equals("undo")) undo();
// else if (cmd.equals("zigzag")) zigzag();
// else if (cmd.equals("flip")) flip();
else if (cmd.equals("r1d")) r1d();
else if (cmd.equals("r1i")) r1i();
else if (cmd.equals("mac")) mac();
else if (cmd.equals("draw")) init();
// else if (cmd.equals("draw w/ bg")) init_bg();
// else if (cmd.equals("remove bg")) remove_bg();
else if (cmd.equals("load")) load();
// else if (cmd.equals("tangle")) tangle("tangle");
// else if (cmd.equals("pretzel")) tangle("pretzel");
// else if (cmd.equals("braid")) tangle("braid");
// else if (cmd.equals("torus")) tangle("torus");
else if (cmd.equals("save link")) saveLink();
else if (cmd.equals("save series")) saveSeries();
else if (cmd.equals("save multi knt")) saveMultiKnt();
// else if (cmd.equals("continue")) continueMultiKnt();
else if (cmd.equals("done multi")) doneMultiKnt();
else if (cmd.equals("save PS")) savePS(false); // arg is bwFlag
else if (cmd.equals("save PS BW")) savePS(true);
else if (cmd.equals("save Jenkins")) saveJenkins();
else if (cmd.equals("save all Jenkins")) saveAllJenkins();
// else if (cmd.equals("save Alex")) saveAlex();
else if (cmd.equals("add")) addInit();
else if (cmd.equals("dup knot")) dupKnot();
else if (cmd.equals("dup link")) dupLink();
else if (cmd.equals("double Y")) doubleY();
else if (cmd.equals("90 ccw")) rotate(90);
else if (cmd.equals("180 ccw")) rotate(180);
else if (cmd.equals("270 ccw")) rotate(270);
else if (cmd.equals("review")) review();
else if (cmd.equals("tricolor")) tricolor();
// else if (cmd.equals("skeleton")) skeleton();
// else if (cmd.equals("simplify")) simplify();
// else if (cmd.equals("bkt poly")) bktPoly();
// else if (cmd.equals("fbkt poly")) fBktPoly();
// else if (cmd.equals("homfly")) homfly();
// else if (cmd.equals("KL-compare")) KL_compare();
// else if (cmd.equals("Kauffman L")) KL();
// else if (cmd.equals("Kauffman unoriented")) Kauffman_unoriented();
// else if (cmd.equals("||")) setState(JOIN_VERTICAL, cancelPopupMenu);
// else if (cmd.equals("=")) setState(JOIN_HORIZONTAL, cancelPopupMenu);
// else if (cmd.equals("nullify")) setState(NULLIFY, cancelPopupMenu);
// else if (cmd.equals("alex")) alex();
// else if (cmd.equals("wirtinger")) wirtinger();
else if (cmd.equals("grid toggle")) toggleGrid();
else if (cmd.equals("copy")) copy();
else if (cmd.equals("paste")) paste();
else if (cmd.equals("add load")) addLoadLink();
else if (cmd.equals("resume")) resume();
else if (cmd.equals("copy/resume")) copyResume();
else if (cmd.equals("prev link")) prevLink();
else if (cmd.equals("next link")) nextLink();
else if (cmd.equals("first link")) firstLink();
else if (cmd.equals("last link")) lastLink();
else if (cmd.equals("prev series")) prevSeries();
else if (cmd.equals("next series")) nextSeries();
else if (cmd.equals("first series")) firstSeries();
else if (cmd.equals("last series")) lastSeries();
// else if (cmd.equals("homfly")) startExpand(HOMFLY);
// else if (cmd.equals("bracket")) startExpand(BRACKET);
// else if (cmd.equals("homfly tree")) loadTree(HOMFLY);
// else if (cmd.equals("bracket tree")) loadTree(BRACKET);
// else if (cmd.equals("expand")) expand();
// else if (cmd.equals("quit")) quitExpand();
// else if (cmd.equals("forward")) forward();
// else if (cmd.equals("backward")) backward();
// else if (cmd.equals("first")) firstInTreeNode();
// else if (cmd.equals("last")) lastInTreeNode();
// else if (cmd.equals("save tree")) saveTree();
// else if (cmd.equals("save tree PS")) saveTreePS();
// else if (cmd.equals("load tree")) loadTree();
// else if (cmd.equals("heading")) getHeading();
// else if (cmd.equals("scale")) getScaleFactor();
else if (cmd.equals("first edge")) firstEdge();
else if (cmd.equals("toggle mark")) markKnot();
else if (cmd.equals("done")) doneSelected();
// else if (cmd.equals("report")) collectTerms();
// else if (cmd.equals("cut")) cut();
// else if (cmd.equals("page size")) getPageSize();
}
void unlinkKnot() {
if (link.getNKnots() < 2) {
statusLabel.setText("only 1 unknot – can’t unlink");
return;
}
reverseOrig = new Link(link);
pushState(UNLINK_KNOT, cancelPopupMenu);
statusLabel.setText("click knot to unlink");
}
void reverseKnot() {
reverseOrig = new Link(link);
if (link.getNKnots() < 2) {
Link orig = new Link(link);
addSeries();
addHistory(orig, link);
link.reverseKnot(0);
pushState(REVERSE_CONFIRM, confirmCancelPopupMenu);
statusLabel.setText("confirm or cancel");
return;
}
pushState(REVERSE_KNOT, confirmCancelPopupMenu);
statusLabel.setText("click knots to reverse");
}
void reflect() {
reverseOrig = new Link(link);
link.makeReflection();
pushState(REFLECT_CONFIRM, confirmCancelPopupMenu);
statusLabel.setText("confirm or cancel");
updateDiagram();
}
/*
void flipHorizontal() {
addHistory(link.makeHorizontalFlip());
link = history[nLinks-1];
currKntName = null;
report(currKntName);
updateDiagram();
}
void flipVertical() {
addHistory(link.makeVerticalFlip());
link = history[nLinks-1];
currKntName = null;
report(currKntName);
updateDiagram();
}
*/
void rotate(int degCcw) {
if (link.getNKnots() == 1) {
Link orig = new Link(link);
try {
link.rotate(0, degCcw);
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
return;
}
tentativeAddHistory(orig, ROTATE_CONFIRM);
return;
}
this.degCcw = degCcw;
pushState(ROTATE, cancelPopupMenu);
statusLabel.setText("click knot to rotate");
}
void doubleY() {
Link orig = new Link(link);
link.doubleY();
updateDiagram();
}
void printLink() {
link.print();
}
void createArrays() {
Edge[] oldea = ea;
double[] oldta = ta;
int[] oldxptx = xptx, oldxpty = xpty;
XOPt[] oldxoa = xoa;
ea = new Edge[linkEdgeMax];
ta = new double[linkEdgeMax];
xptx = new int[linkEdgeMax];
xpty = new int[linkEdgeMax];
xoa = new XOPt[linkEdgeMax];
for (int ii = 0; ii < intersectCt; ii++) {
ea[ii] = oldea[ii]; ta[ii] = oldta[ii];
xptx[ii] = oldxptx[ii]; xpty[ii] = oldxpty[ii];
xoa[ii] = oldxoa[ii];
}
}
void addSeries() {
if (nSeries == seriesMax) {
seriesMax *= 2;
int[] temp = new int[seriesMax];
for (int ii = 0; ii < seriesStart.length; ii++)
temp[ii] = seriesStart[ii];
seriesStart = temp;
String[] stringTemp = new String[seriesMax];
for (int i = 0; i < seriesStart.length; i++)
stringTemp[i] = seriesName[i];
seriesName = stringTemp;
}
seriesStart[nSeries++] = nLinks;
currentSeries = nSeries - 1;
}
void addHistory(Link link) {
if (nLinks == historyMax) {
historyMax *= 2;
Link[] temp = new Link[historyMax];
for (int ii = 0; ii < history.length; ii++)
temp[ii] = history[ii];
history = temp;
}
history[nLinks++] = link;
currentLink = nLinks - 1;
currKntName = null;
}
void addHistory(Link orig, Link newLink) {
// if (root != null) { // in tree expansion mode
// currentNode.addHistory(orig, newLink);
// return;
// }
history[nLinks-1] = orig;
addHistory(newLink);
}
void initState() {
link = new Link();
addSeries();
addHistory(link);
linkEdgeCt = 0;
intersectCt = 0;
pts = new Vector();
edges = new Vector();
completeKnot();
setPopupMenu(completeKnotPopupMenu);
statusLabel.setText("between knots");
}
public void init() {
currKntName = null;
initState();
updateInfoAndDiagram();
}
/*
void loadBackground() {
LoadFileDialog lfd = new LoadFileDialog(frame);
try {
BufferedReader br = lfd.getLoadFile("Load Background", "*.gif");
String backgroundName = lfd.getLoadFileName();
background = getToolkit().getImage(backgroundName);
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(background, 0);
tracker.waitForID(0);
}
catch (Exception anyExc) {
statusLabel.setText("load background aborted");
return;
}
}
public void init_bg() {
loadBackground();
init();
}
public void remove_bg() {
background = null;
updateDiagram();
}
*/
void addInit() {
link = new Link(link);
addSeries();
addHistory(link);
if (linkEdgeMax < 2*link.totalCrossings) {
linkEdgeMax = 2*link.totalCrossings;
createArrays();
}
linkEdgeCt = link.totalEdges;
intersectCt = 0;
link.nOldKnots = link.getNKnots();
for (int i = 0; i < link.getNKnots(); i++) {
XPt p = link.getFirstXPt(i);
if (p == null) continue;
XPt p1 = p;
do {
if (p instanceof XOPt) {
Point loc = p.getLocation();
xptx[intersectCt] = loc.x;
xpty[intersectCt] = loc.y;
intersectCt++;
}
p = p.getNext();
} while (p != p1);
}
completeKnot();
setPopupMenu(betweenKnotsPopupMenu);
statusLabel.setText("between knots");
}
void makeOffscreen() {
MediaTracker tracker = new MediaTracker(this);
int curWidth = preferredSize.width,
curHeight = preferredSize.height;
offscreen = createImage(curWidth, curHeight);
tracker.addImage(offscreen, 0);
try { tracker.waitForID(0); }
catch (InterruptedException anyExc) { }
Graphics og = offscreen.getGraphics();
paint(og);
}
void dupKnot() {
setPopupMenu(cancelPopupMenu);
makeOffscreen();
if (link.getNKnots() == 1) {
lastDupPoint = null;
nOldKnots = link.dupChosenKnot(link.getFirstEdge(0));
state = DUP_KNOT_MOVE;
Graphics g = offscreen.getGraphics();
link.xorDraw(g, nOldKnots, true);
updateInfoAndDiagram();
statusLabel.setText("drag to move new copy");
return;
}
state = DUP_KNOT_CHOOSE;
statusLabel.setText("click knot to duplicate");
}
void dupLink() {
setPopupMenu(cancelPopupMenu);
makeOffscreen();
lastDupPoint = null;
nOldKnots = link.dupLink();
state = DUP_KNOT_MOVE;
Graphics g = offscreen.getGraphics();
link.xorDraw(g, nOldKnots, true);
updateInfoAndDiagram();
statusLabel.setText("drag to move new copy");
return;
}
void report(String seriesName) {
infoLabel.setText("#" + currentSeries + ":" + (currentLink - seriesStart[currentSeries])
+ " " + seriesName + ": " + "#comps = "
+ link.getNKnots() + " #crossings = " + link.totalCrossings
+ " writhe = " + link.writhe()
+ " self-writhe = " + link.selfWrithe()
+ " linking number = " + link.linkingNumber()
);
}
void loadFromFile(BufferedReader br) throws Exception {
LinkReader lr = new LinkReader(br);
int nLinks = lr.getNLinks();
System.out.println("#links in file = " + nLinks);
if (nLinks <= 0) return;
addSeries();
for (int i = 0; i < nLinks; i++) {
link = lr.loadLink();
// System.out.println("i = " + i + " #knots = " + link.nKnots);
// System.out.println("loaded link is:");
// link.print();
// System.out.println("end of link");
addHistory(link);
}
System.out.println("finished loading from file lastLoadName = " + lastLoadName);
currKntName = lastLoadName;
if (currKntName.toUpperCase().endsWith(".KNT"))
currKntName = currKntName.substring(0, currKntName.length()-4);
if (currKntName.toUpperCase().endsWith("-SER"))
currKntName = currKntName.substring(0, currKntName.length()-4);
// System.out.println("currentSeries = " + currentSeries);
seriesName[currentSeries] = currKntName;
try { br.close(); } catch (Exception anyExc) { }
state = COMPLETE;
setPopupMenu(completePopupMenu);
System.out.println("about to call report");
report(currKntName);
updateDiagram();
System.out.println("at end of loadFromFile state = " + state);
}
void loadFromFileName(String name) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(name));
lastLoadName = Util.getLastComponent(name);
loadFromFile(br);
}
void load() {
LoadFileDialog lfd = new LoadFileDialog(frame);
BufferedReader br;
try {
br = lfd.getLoadFile("Load Links", "*.knt");
lastLoadName = Util.getLastComponent(lfd.getLoadFileName());
System.out.println("loading from: " + lastLoadName);
loadFromFile(br);
System.out.println("returned from loadFromFile");
// completePopupMenu.show(this, 200, 200);
}
catch (Exception anyExc) {
statusLabel.setText("load aborted");
return;
}
}
void load(String filename) {
BufferedReader br;
try {
br = new BufferedReader(new FileReader(filename));
loadFromFile(br);
}
catch (Exception anyExc) {
statusLabel.setText("load aborted");
return;
}
}
void addLoadLink() {
LoadFileDialog lfd = new LoadFileDialog(frame);
BufferedReader br = null;
Link linkToAdd = null;
try {
br = lfd.getLoadFile("Load Links", "*.knt");
LinkReader lr = new LinkReader(br);
int nLinks = lr.getNLinks();
if (nLinks <= 0) return;
for (int ii = 0; ii < nLinks; ii++) {
linkToAdd = lr.loadLink();
}
}
catch (Exception anyExc) {
statusLabel.setText("load aborted");
return;
}
finally {
try { br.close(); } catch (Exception anyExc) { }
}
paste(linkToAdd);
}
/*
void tangle(String title) {
// title could be "tangle" or "pretzel" or "braid" or "torus"
TangleDialog td = new TangleDialog(frame, title);
if (td.isCancelled()) {
statusLabel.setText(title + " cancelled");
return;
}
int[] tangleSeq = td.getTangleSeq();
if (tangleSeq == null) {
statusLabel.setText("illegal " + title + " sequence");
return;
}
for (int i = 0; i < tangleSeq.length; i++)
System.out.print(tangleSeq[i] + " ");
System.out.println();
addSeries();
if (title.equals("tangle")) ; // link = TangleUnit.makeTangle(tangleSeq);
else if (title.equals("pretzel")) ; // link = TangleUnit.makePretzel(tangleSeq);
else if (title.equals("braid")) {
boolean ok = true;
for (int i = 0; i < tangleSeq.length; i++)
if (tangleSeq[i] == 0) {
ok = false;
break;
}
if (!ok) {
statusLabel.setText("0 not allowed in braid word");
return;
}
// link = TangleUnit.makeBraid(tangleSeq);
}
else if (title.equals("torus")) {
if (tangleSeq.length != 2) {
statusLabel.setText("expect 2 parameters for torus");
return;
}
int n = tangleSeq[0];
int k = tangleSeq[1];
if (n < 1) {
statusLabel.setText("torus: n must be >= 1");
return;
}
if (k < 2) {
statusLabel.setText("torus: k must be >= 2");
return;
}
// link = TangleUnit.makeTorus(n, k);
}
addHistory(link);
currKntName = null;
state = COMPLETE;
setPopupMenu(completePopupMenu);
report("<noname>");
updateDiagram();
}
*/
/*
public BufferedWriter fileToUse(String fileName) {
// check the given file name to see if it already exists
// if not, try to create file with that name
// if it already exists, show a dialog to ask user's
// intention
BufferedWriter bw = null;
String theName = fileName;
ExistsDialog existsDialog = null;
while (bw == null) {
File theFile = new File(theName);
if (theFile.exists() && !overwriteAllFlag) {
existsDialog = new ExistsDialog(frame, ExistsDialog.EXISTS, theName, 200, 150);
if (existsDialog.cancelAllChosen())
cancelAllFlag = true;
if (cancelAllFlag || existsDialog.cancelChosen()) {
return bw; // it's null
}
if (existsDialog.newNameChosen()) {
theName = existsDialog.getName();
continue;
}
if (existsDialog.overwriteAllChosen())
overwriteAllFlag = true;
}
// if we got here, try opening file with theName
boolean sameName = true;
while (sameName) {
try {
bw = new BufferedWriter(new FileWriter(theName));
if (bw == null) throw new Exception("failed to create: " + theName);
break;
}
catch (Exception anyExc) {
existsDialog = new ExistsDialog(frame, ExistsDialog.CREATE_FAIL, theName, 200, 150);
}
if (existsDialog.overwriteChosen()) continue; // retry
if (existsDialog.cancelAllChosen()) cancelAllFlag = true;
if (cancelAllFlag || existsDialog.cancelChosen())
return (BufferedWriter) null;
if (existsDialog.newNameChosen()) {
theName = existsDialog.getName();
sameName = false;
}
} // while (sameName)
} // while (bw == null)
return bw;
}
*/
public BufferedWriter fileToUse(String fileName) throws Exception {
BufferedWriter bw = new BufferedWriter(new FileWriter(fileName));
return bw;
}
/*
void saveLink() {
overwriteAllFlag = cancelAllFlag = false;
String root = "";
if (currKntName != null) {
root = currKntName;
if (root.toUpperCase().endsWith(".KNT"))
root = root.substring(0, root.length()-4);
}
SaveLinkDialog sld = new SaveLinkDialog(frame, SaveLinkDialog.SAVE_LINK, root, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getName();
currKntName = nameRoot;
report(currKntName);
String dyName = sld.getDirectory();
if (!dyName.equals("")) {
if (!dyName.endsWith(File.separator)) dyName += File.separator;
nameRoot = dyName + nameRoot;
}
if (sld.gaussChosen()) {
BufferedWriter gaussFile = fileToUse(nameRoot + ".gss");
if (gaussFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveGauss(gaussFile);
}
if (sld.jenkinsChosen()) {
BufferedWriter jenkinsFile = fileToUse(nameRoot + ".jnk");
if (jenkinsFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveJenkins(jenkinsFile);
}
if (sld.geometricChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + ".knt");
if (kntFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveGeometric(kntFile);
}
if (sld.PLChosen()) {
BufferedWriter plFile = fileToUse(nameRoot + ".pl");
if (plFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePL(plFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + ".ps");
if (psColorFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePS(psColorFile, LinkWriter.COLOR);
}
if (sld.psGreyScaleChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs.ps");
if (psGreyScaleFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePS(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBlackChosen()) {
BufferedWriter psBlackFile = fileToUse(nameRoot + "-bw.ps");
if (psBlackFile == null) { // cancelled
if (cancelAllFlag) return;
}
else savePS(psBlackFile, LinkWriter.BLACK);
}
if (sld.uniAlexChosen()) {
BufferedWriter uniAlexFile = fileToUse(nameRoot + "-uni.txt");
if (uniAlexFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveAlex(uniAlexFile, 1); // 1 for univariate
}
if (sld.multiAlexChosen()) {
BufferedWriter multiAlexFile = fileToUse(nameRoot + "-multi.txt");
if (multiAlexFile == null) { // cancelled
if (cancelAllFlag) return;
}
else saveAlex(multiAlexFile, 2); // 2 for multivariate
}
}
*/
void saveLink() {
System.out.println("in saveLink");
SaveLinkDialog sld = new SaveLinkDialog(frame, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getNameRoot();
try {
if (sld.geomChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + ".knt");
if (kntFile == null) return;
saveGeometric(kntFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + ".ps");
if (psColorFile == null) return;
savePS(psColorFile, LinkWriter.COLOR);
}
if (sld.psGSChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs.ps");
if (psGreyScaleFile == null) return;
savePS(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBWChosen()) {
BufferedWriter psBlackFile = fileToUse(nameRoot + "-bw.ps");
if (psBlackFile == null) return;
savePS(psBlackFile, LinkWriter.BLACK);
}
if (sld.jenkinsChosen()) {
BufferedWriter jenkinsFile = fileToUse(nameRoot + ".jnk");
if (jenkinsFile == null) { // cancelled
// if (cancelAllFlag) return;
return;
}
else saveJenkins(jenkinsFile);
}
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
}
void saveGeometric(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
System.out.println("about to call saveNLinks");
lw.saveNLinks(1);
System.out.println("after saveNLinks; about to call saveLink nKnots = "
+ link.nKnots);
lw.saveLink(link);
System.out.println("after saveLink");
bw.close();
}
catch (Exception anyExc) {
statusLabel.setText("save aborted");
return;
}
statusLabel.setText("save completed");
}
void savePS(BufferedWriter bw, int colorType) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.writeLine("/Times-Roman findfont 12 scalefont setfont");
lw.writeLine("30 0 translate");
int transIndex = 0;
lw.writeLine("gsave");
lw.writeLine("0.5 0.5 scale");
lw.writeLine(translations[transIndex++]);
lw.saveRoundPS(link, boxWd, boxHt, arcRadius, colorType);
lw.writeLine("grestore");
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PS aborted");
return;
}
statusLabel.setText("save PS completed");
}
/*
void saveSeries() {
overwriteAllFlag = cancelAllFlag = false;
String root = "";
if (currKntName != null) {
root = currKntName;
if (root.toUpperCase().endsWith(".KNT"))
root = root.substring(0, root.length()-4);
}
SaveLinkDialog sld = new SaveLinkDialog(frame, SaveLinkDialog.SAVE_SERIES, root, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getName();
currKntName = nameRoot;
report(currKntName);
String dyName = sld.getDirectory();
if (!dyName.equals("")) {
if (!dyName.endsWith(File.separator)) dyName += File.separator;
nameRoot = dyName + nameRoot;
}
if (sld.geometricChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + "-ser.knt");
if (kntFile == null) {
if (cancelAllFlag) return;
}
else saveGeometricSeries(kntFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + "-ser.ps");
if (psColorFile == null) {
if (cancelAllFlag) return;
}
else savePSSeries(psColorFile, LinkWriter.COLOR);
}
if (sld.psGreyScaleChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs-ser.ps");
if (psGreyScaleFile == null) {
if (cancelAllFlag) return;
}
else savePSSeries(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBlackChosen()) {
BufferedWriter psBlackile = fileToUse(nameRoot + "-bw-ser.ps");
if (psGreyScaleFile == null) {
if (cancelAllFlag) return;
}
else savePSSeries(psBlackFile, LinkWriter.BLACK);
}
}
*/
void saveSeries() {
SaveLinkDialog sld = new SaveLinkDialog(frame, 200, 150);
if (sld.cancelled()) return;
String nameRoot = sld.getNameRoot();
try {
if (sld.geomChosen()) {
BufferedWriter kntFile = fileToUse(nameRoot + "-ser.knt");
if (kntFile == null) return;
saveGeometricSeries(kntFile);
}
if (sld.psColorChosen()) {
BufferedWriter psColorFile = fileToUse(nameRoot + "-ser.ps");
if (psColorFile == null) return;
savePSSeries(psColorFile, LinkWriter.COLOR);
}
if (sld.psGSChosen()) {
BufferedWriter psGreyScaleFile = fileToUse(nameRoot + "-gs-ser.ps");
if (psGreyScaleFile == null) return;
savePSSeries(psGreyScaleFile, LinkWriter.GREYSCALE);
}
if (sld.psBWChosen()) {
BufferedWriter psBlackFile = fileToUse(nameRoot + "-bw-ser.ps");
if (psBlackFile == null) return;
savePSSeries(psBlackFile, LinkWriter.BLACK);
}
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
}
void saveGeometricSeries(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) - start;
lw.saveNLinks(n);
for (int i = 0; i < n; i++) {
lw.saveLink(history[start+i]);
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save series aborted");
return;
}
statusLabel.setText("save series completed");
}
void savePSSeries(BufferedWriter bw, int colorType) {
try {
LinkWriter lw = new LinkWriter(bw);
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) - start;
lw.writeLine("/Times-Roman findfont 12 scalefont setfont");
lw.writeLine("30 0 translate");
int transIndex = 0;
for (int i = 0; i < n; i++) {
lw.writeLine("gsave");
lw.writeLine("0.5 0.5 scale");
lw.writeLine(translations[transIndex++]);
lw.writeLine("0 " + (boxHt+3) + " moveto (#" + (i+1) + ") show");
lw.saveRoundPS(history[start+i], boxWd, boxHt, arcRadius, colorType);
lw.writeLine("grestore");
if (transIndex >= translations.length) {
transIndex = 0;
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PS series aborted");
return;
}
statusLabel.setText("save PS series completed");
}
void saveJenkins(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Jenkins aborted");
return;
}
statusLabel.setText("save Jenkins completed");
}
/*
void saveGauss(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.saveGauss(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Gauss aborted");
return;
}
statusLabel.setText("save Gauss completed");
}
void savePL(BufferedWriter bw) {
try {
LinkWriter lw = new LinkWriter(bw);
lw.savePL(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PL aborted");
return;
}
statusLabel.setText("save PL completed");
}
void saveAlex(BufferedWriter bw, int flag) {
try {
link.saveAlex(bw, flag);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Alex aborted");
return;
}
statusLabel.setText("save Alex completed");
}
*/
/*
void save() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Links", "knt");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
lastKntName = sfd.getFileName();
LinkWriter lw = new LinkWriter(bw);
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) - start;
lw.saveNLinks(n);
for (int ii = 0; ii < n; ii++) {
lw.saveLink(history[start+ii]);
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save aborted");
return;
}
statusLabel.setText("save completed");
}
*/
void saveMultiKnt() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Multi", "knt");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
multiKntFilename = sfd.getFileName();
if (!multiKntFilename.toLowerCase().endsWith(".knt"))
throw new Exception("Filename not ending in .knt");
underlinePos = multiKntFilename.lastIndexOf('_');
if (underlinePos < 0) throw new Exception("No _ in filename");
int dotPos = multiKntFilename.length() - 4;
if (underlinePos == dotPos-1)
throw new Exception("_ immediately preceding .knt");
for (int ii = underlinePos+1; ii < dotPos; ii++)
if (!Character.isDigit(multiKntFilename.charAt(ii)))
throw new Exception("Nondigit between _ and .knt");
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save aborted");
return;
}
statusLabel.setText("save completed");
setState(MULTI_KNT, multiKntPopupMenu);
}
void saveCurrentLink(String fileName) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(fileName));
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save aborted " + fileName);
return;
}
statusLabel.setText("save completed " + fileName);
}
void continueMultiKnt() {
setState(MULTI_KNT_UNLINK, cancelPopupMenu);
statusLabel.setText("click knot to unlink");
}
void doneMultiKnt() {
setState(COMPLETE, completePopupMenu);
statusLabel.setText("Save Multi Knt complete");
}
void savePS(boolean bwFlag) {
SaveFileDialog sfd = new SaveFileDialog(frame,
"Save Ps" + (bwFlag ? "_BW" : ""), "ps");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
LinkWriter lw = new LinkWriter(bw);
/* lw.writeLine("%!PS-Adobe-2.0");
lw.writeLine("%%Creator: dvips 5.58 Copyright 1986, 1994 " +
"Radical Eye Software");
lw.writeLine("%%Title: binstr.dvi");
*/
int start = seriesStart[currentSeries];
int n = ( (currentSeries < nSeries-1) ?
seriesStart[currentSeries+1] : nLinks ) -start;
lw.writeLine("/Times-Roman findfont 12 scalefont setfont");
int transIndex = 0;
for (int ii = 0; ii < n; ii++) {
lw.writeLine("gsave");
lw.writeLine(translations[transIndex++]);
lw.writeLine("0 " + (boxHt+3) + " moveto (#" + (ii+1) + ") show");
lw.saveRoundPS(history[start+ii], boxWd, boxHt, arcRadius,
bwFlag ? LinkWriter.BLACK : LinkWriter.COLOR);
lw.writeLine("grestore");
if (transIndex >= translations.length) {
transIndex = 0;
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
}
if (transIndex > 0) {
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save PS aborted");
return;
}
statusLabel.setText("save PS completed");
}
void saveJenkins() {
SaveFileDialog sfd = new SaveFileDialog(frame,
"Save Jenkins", ".jnk");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(link);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save Jenkins aborted");
return;
}
statusLabel.setText("save Jenkins completed");
}
void saveAllJenkins() {
if (link == null) {
statusLabel.setText("save all Jenkins aborted – no link");
return;
}
if (lastKntName == null) {
statusLabel.setText("save all Jenkins aborted – no name");
return;
}
int n = link.getNKnots();
if (n < 2) {
statusLabel.setText("save all Jenkins aborted – one knot");
return;
}
String nameRoot = lastKntName;
if (nameRoot.endsWith(".knt") || nameRoot.endsWith(".KNT"))
nameRoot = nameRoot.substring(0, nameRoot.length()-4);
int numOrientations = 1;
for (int ii = 0; ii < n-1; ii++) numOrientations *= 2;
int curMask = 0;
int prevMask = 0;
Link link1 = new Link(link);
while (curMask < numOrientations) {
int diff = curMask ^ prevMask;
for (int ii = 0; diff != 0; ii++, diff /= 2) {
if ((diff & 1) != 0) link1.reverseKnot(ii);
}
BufferedWriter bw;
try {
bw = new BufferedWriter(new FileWriter(
nameRoot + "-" + curMask + ".jnk"));
LinkWriter lw = new LinkWriter(bw);
lw.saveJenkins(link1);
bw.close();
bw = new BufferedWriter(new FileWriter(
nameRoot + "-" + curMask + ".knt"));
lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link1);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save all Jenkins aborted");
return;
}
prevMask = curMask;
curMask++;
}
statusLabel.setText("save all Jenkins completed");
}
/*
void saveAlex() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Alex", ".txt");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
link.saveAlex(bw);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save alex aborted");
return;
}
statusLabel.setText("save alex completed");
}
void saveTree() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Tree",
(expandType == HOMFLY) ? "htr" : "btr");
BufferedWriter bw;
try {
bw = sfd.getSaveFile();
LinkWriter lw = new LinkWriter(bw);
root.saveTree(lw);
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save tree aborted");
return;
}
statusLabel.setText("save tree completed");
}
void saveTreePS() {
SaveFileDialog sfd = new SaveFileDialog(frame, "Save Tree PS", "ps");
BufferedWriter bw, aw;
try {
bw = sfd.getSaveFile();
String auxName = sfd.getFileName();
int dotPos = auxName.lastIndexOf('.');
if (dotPos >= 0) auxName = auxName.substring(0, dotPos);
auxName += ".aux";
aw = new BufferedWriter(new FileWriter(auxName));
LinkWriter lw = new LinkWriter(bw);
lw.setAuxWriter(aw);
lw.setPSPageSize(pageWidth, pageHeight);
// lw.saveTreePS(scaleFactor);
lw.saveTreePSInit(scaleFactor);
root.saveTreePS(lw, scaleFactor, expandType == HOMFLY);
lw.wrapUp();
bw.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("save tree PS aborted");
return;
}
statusLabel.setText("save tree PS completed");
}
void loadTree(int expandType) {
LoadFileDialog lfd = new LoadFileDialog(frame);
BufferedReader br;
try {
br = lfd.getLoadFile("Load Tree",
(expandType == HOMFLY) ? "*.htr" : "*.btr");
LinkReader lr = new LinkReader(br);
currentNode = root = TreeNode.loadTree(lr);
link = currentNode.getCurrentLink();
br.close();
}
catch (Exception anyExc) {
statusLabel.setText("load tree aborted");
return;
}
statusLabel.setText("load tree completed");
this.expandType = expandType;
setState(EXPAND, expandPopupMenu);
}
void getHeading() {
headingDialog = new Dialog(frame, "Node heading", true);
headingTF = new TextField(40);
headingDialog.add(headingTF, BorderLayout.CENTER);
headingTF.addActionListener(this);
headingDialog.setLocation(100, 100);
headingTF.setText(currentNode.getHeading());
headingDialog.pack();
headingDialog.show();
}
*/
void getScaleFactor() {
scaleFactorDialog = new Dialog(frame, "Scale Factor", true);
scaleFactorTF = new TextField(20);
scaleFactorDialog.add(scaleFactorTF, BorderLayout.CENTER);
scaleFactorTF.addActionListener(this);
scaleFactorDialog.setLocation(100, 100);
scaleFactorTF.setText("" + scaleFactor);
scaleFactorDialog.pack();
scaleFactorDialog.setVisible(true);
}
void getPageSize() {
pageSizeDialog = new Dialog(frame, "Page Size", true);
pageSizeTF = new TextField(20);
pageSizeDialog.add(pageSizeTF, BorderLayout.CENTER);
scaleFactorTF.addActionListener(this);
scaleFactorDialog.setLocation(100, 100);
pageSizeDialog.pack();
pageSizeDialog.show();
}
/*
void collectTerms() {
Hashtable ht = new Hashtable();
if (expandType == HOMFLY) {
root.homflyCollectTerms(LPoly2.ONE, ht);
for (Enumeration e = ht.keys(); e.hasMoreElements(); ) {
String s = (String) e.nextElement();
LPoly2 coeff = (LPoly2) ht.get(s);
System.out.print(s + ": ");
coeff.print();
}
}
else {
root.bracketCollectTerms(LPoly.ONE, ht);
for (Enumeration e = ht.keys(); e.hasMoreElements(); ) {
String s1 = (String) e.nextElement();
LPoly coeff1 = (LPoly) ht.get(s1);
System.out.print(s1 + ": ");
coeff1.print();
}
}
}
void cut() {
if (currentNode.currentIsLast() && currentNode.lson != null) {
currentNode.lson = currentNode.rson = null;
currentNode.expandedCrossing = null;
}
else if (currentNode.currentLink > 0) {
currentNode.truncate();
link = currentNode.getCurrentLink();
selectEdge = null;
}
updateDiagram();
}
*/
void firstEdge() {
pushState(FIRST_EDGE, donePopupMenu);
}
void markKnot() {
pushState(MARK_KNOT, donePopupMenu);
}
void doneSelected() {
if (state == REVERSE_KNOT) {
addSeries();
addHistory(reverseOrig, link);
}
selectEdge = null;
popState();
updateInfoAndDiagram();
}
public Dimension getMinimumSize() {
return new Dimension(10, 10);
}
public Dimension getPreferredSize() {
return preferredSize;
}
public void setLink(Link link) {
this.link = link;
}
void alternate() {
if (state != CROSSING) return;
altFlag = true;
setPopupMenu(nonaltPopupMenu);
}
void nonAlternate() {
if (state != CROSSING) return;
altFlag = false;
setPopupMenu(altPopupMenu);
}
public void exitPressed() {
System.exit(0);
}
public void completePressed() {
System.out.println("in completePressed state = " + state);
if (state == BETWEEN_KNOTS) {
if (intersectCt == 0) completeLink();
else {
state = CROSSING; altFlag = false;
setPopupMenu(altPopupMenu);
updateDiagram();
}
}
else if (state == R1I) {
if (nChosenEdges < 1) {
statusLabel.setText("1 edge needed for r1i");
return;
}
else if (nChosenPoints < 2) {
statusLabel.setText("2 points needed for r1i");
return;
}
if (nChosenEdges < 2) chosenEdge2 = chosenEdge1;
try {
link.firstSelectedEdge = chosenEdge1;
link.lastSelectedEdge = chosenEdge2;
Link orig = new Link(link);
link.r1i(chosenEdge1, chosenEdge2, chosenPoints, nChosenPoints);
link.clearSelectedEdges();
addHistory(orig, link);
statusLabel.setText("toggle crossing or confirm");
}
catch (Exception anyExc) {
link.clearSelectedEdges();
statusLabel.setText(anyExc.getMessage());
return;
}
state = R1I_CROSSING;
setPopupMenu(confirmPopupMenu);
updateDiagram();
}
else if (state == MAC) {
System.out.println("in completePressed() state is MAC #chosen edges = "
+ nChosenEdges);
if (nChosenEdges < 1) {
statusLabel.setText("1 edge needed for mac");
return;
}
if (nChosenEdges < 2) chosenEdge2 = chosenEdge1;
try {
link.firstSelectedEdge = chosenEdge1;
link.lastSelectedEdge = chosenEdge2;
System.out.println("about to construct copy of link");
Link orig = new Link(link);
System.out.println("about to call Link.mac");
link.mac(chosenEdge1, chosenEdge2, chosenPoints, nChosenPoints);
System.out.println("back from Link.mac");
link.clearSelectedEdges();
addHistory(orig, link);
}
catch (Exception anyExc) {
link.clearSelectedEdges();
statusLabel.setText(anyExc.getMessage());
return;
}
if (link.macCompleted()) {
statusLabel.setText("mac completed");
popState();
}
else {
statusLabel.setText("toggle crossing or confirm");
state = MAC_CROSSING;
setPopupMenu(confirmPopupMenu);
}
updateInfoAndDiagram();
}
}
public void completeVert(){
if (nChosenEdges == 0 || nChosenPoints < 1) {
statusLabel.setText("complete | not applicable");
return;
}
Point p = ( (nChosenEdges == 1) ? chosenEdge1 : chosenEdge2 ).
getOutPt().getLocation();
p = cornerVert(lastPtLoc, p);
chosenPoints[nChosenPoints++] = p;
completePressed();
}
public void completeHoriz() {
if (nChosenEdges == 0 || nChosenPoints < 1) {
statusLabel.setText("complete - not applicable");
return;
}
Point p = ( (nChosenEdges == 1) ? chosenEdge1 : chosenEdge2 ).
getOutPt().getLocation();
p = cornerHoriz(lastPtLoc, p);
chosenPoints[nChosenPoints++] = p;
completePressed();
}
public void cancelPressed() {
switch (state) {
case COMPLETE: case R1I: // case R2I: case R3: case STRAIGHTEN:
case MAC: case UNLINK_KNOT: case ROTATE:
break;
case UNLINK_CONFIRM: case ROTATE_CONFIRM: case STRAIGHTEN:
case REVERSE_CONFIRM: case REFLECT_CONFIRM:
link = history[(--nLinks) - 1];
break;
case RECT_UNKNOT: case DUP_KNOT_CHOOSE:
cancelKnot();
return;
case CLIP_RECT:
rectStage = NONE;
setState(EXPAND, expandPopupMenu);
return;
case MULTI_KNT_UNLINK:
statusLabel.setText("Save Multi Knt cancelled");
setState(COMPLETE, completePopupMenu);
return;
case MULTI_KNT_CONFIRM:
link = history[(--nLinks) - 1];
statusLabel.setText("click knot to unlink");
setState(MULTI_KNT_UNLINK, cancelPopupMenu);
selectEdge = null;
updateDiagram();
return;
/*
case ITERATE:
UnitLink ul = new UnitLink(link);
Iterate.printUnitLink(ul);
rectStage = NONE;
statusLabel.setText("complete");
setState(COMPLETE, completePopupMenu);
updateDiagram();
return;
*/
}
popState();
selectEdge = null;
updateDiagram();
statusLabel.setText("");
}
public void tricolor() {
if (link.isSplit()) {
statusLabel.setText("link split");
return;
}
else if (!link.tricolorable()) {
statusLabel.setText("link not tricolorable");
return;
}
pushState(TRICOLOR, cancelPopupMenu);
updateDiagram();
statusLabel.setText("tricolor: " + link.getNStrands() + " strands");
cancelPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
/*
public void skeleton() {
skeletonCopy = link.makeSkeletonCopy();
state = SKELETON;
setPopupMenu(cancelPopupMenu);
updateDiagram();
cancelPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
public void simplify() {
skeletonCopy = link.makeSkeletonCopy();
skeletonCopy.simplifyIAndII();
state = SIMPLIFY;
setPopupMenu(cancelPopupMenu);
updateDiagram();
cancelPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
public void bktPoly() {
skeletonCopy = link.makeSkeletonCopy();
LPoly p = Link.bktPoly(skeletonCopy);
System.out.println("bkt poly:");
p.print();
}
public void fBktPoly() {
skeletonCopy = link.makeSkeletonCopy();
LPoly p = Link.fBktPoly(skeletonCopy);
System.out.println("fbkt poly:");
p.print();
}
public void homfly() {
Date start = new Date();
skeletonCopy = link.makeSkeletonCopy();
GLink gSkeletonCopy = new GLink(skeletonCopy);
LPoly2 p = gSkeletonCopy.homfly_sta();
System.out.println("homfly:");
p.print();
System.out.println("time (ms): " +
((new Date()).getTime() - start.getTime()) );
}
public void KL() {
Date start = new Date();
skeletonCopy = link.makeSkeletonCopy();
GLink gSkeletonCopy = new GLink(skeletonCopy);
LPoly2 p = gSkeletonCopy.KL_sta();
System.out.println("Kauffman-L:");
p.print();
System.out.println("time (ms): " +
((new Date()).getTime() - start.getTime()) );
}
public void Kauffman_unoriented() {
Date start = new Date();
GLink g = new GLink(link);
LPoly2 p = g.Kauffman_unoriented();
System.out.println("Kauffman-unoriented:");
p.print();
System.out.println("time (ms): " +
((new Date()).getTime() - start.getTime()) );
}
*/
void setState(int newState, PopupMenu newPopupMenu) {
state = newState;
setPopupMenu(newPopupMenu);
updateDiagram();
if (newState == MULTI_KNT || newState == REVERSE_CONFIRM)
newPopupMenu.show(this, lastClickedPoint.x, lastClickedPoint.y);
}
void pushState(int newState, PopupMenu newPopupMenu) {
oldState = state;
oldPopupMenu = currentPopupMenu;
setState(newState, newPopupMenu);
}
void popState() {
setState(oldState, oldPopupMenu);
}
/*
void joinHorV(Point p) {
XOPt xp = link.findXOPt(p);
if (xp != null) {
Link orig = new Link(link);
link.print();
link = link.makeSkeletonCopy();
System.out.println("skeletonized");
link.print();
System.out.println("***");
xp = link.findXOPt(p);
if (state == JOIN_VERTICAL) link.joinVertical(xp);
else link.joinHorizontal(xp);
link.print();
history[nLinks-1] = orig;
addHistory(link);
}
else{
statusLabel.setText("point clicked not a crossing");
}
}
void nullify(Point p) {
XOPt xp = link.findXOPt(p);
if (xp != null) {
Link orig = new Link(link);
xp = link.findXOPt(p);
link.nullify(xp);
addHistory(orig, link);
}
else {
statusLabel.setText("point clicked not a crossing");
}
}
void alex() {
try {
int[] res = link.alex();
for (int ii = 0; ii < res.length; ii++)
System.out.print(res[ii] + " ");
System.out.println();
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
}
}
void printMapleSeq(int[] vec) {
System.out.print("[" + vec[0]);
for (int i = 1; i < vec.length; i++)
System.out.print("," + vec[i]);
System.out.print("]");
}
*/
void wirtinger() {
/*
try {
int[][] wirt = link.getWirtinger();
System.out.println("[");
for (int i = 0; i < wirt.length-1; i++) {
printMapleSeq(wirt[i]);
System.out.println(",");
}
printMapleSeq(wirt[wirt.length-1]);
System.out.println();
System.out.println("]");
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
}
*/
}
/*
void startExpand(int expandType) {
// saveTree();
// addSeries();
// addHistory(currentNode.getCurrentLink());
// history[nLinks-1].clearSelectedEdges();
// link = history[nLinks-1];
currentNode = root = new TreeNode((TreeNode) null, link);
selectEdge = null;
this.expandType = expandType;
setState(EXPAND, expandPopupMenu);
}
void quitExpand() {
saveTree();
addSeries();
addHistory(currentNode.getCurrentLink());
history[nLinks-1].clearSelectedEdges();
link = history[nLinks-1];
currentNode = root = null;
selectEdge = null;
setState(COMPLETE, completePopupMenu);
}
void forward() {
currentNode.forward();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void backward() {
currentNode.backward();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void firstInTreeNode() {
currentNode.first();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void lastInTreeNode() {
currentNode.last();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void upTree() {
TreeNode res = currentNode.up();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void downTree() {
TreeNode res = currentNode.down();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void sibling() {
TreeNode res = currentNode.sibling();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void nextNode() {
TreeNode res = currentNode.next();
if (res == null) return;
currentNode = res;
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
}
void expand() {
if (!currentNode.okToExpand()) {
statusLabel.setText("can't expand");
return;
}
pushState(EXPAND_CROSSING, cancelPopupMenu);
}
void expandCrossing(Point p) {
XOPt xp = link.findXOPt(p);
if (xp == null) {
statusLabel.setText("point clicked is not a crossing");
}
else if (expandType == HOMFLY) {
Link switched = new Link(link);
xp = switched.findXOPt(p);
xp.toggle();
switched.wrapUp();
Link nullified = new Link(link);
xp = nullified.findXOPt(p);
currentNode.expand(p, switched, nullified);
downTree();
setState(EXPAND, expandPopupMenu);
}
else {
Link vert = new Link(link);
xp = vert.findXOPt(p);
vert.joinVertical(xp);
Link horiz = new Link(link);
xp = horiz.findXOPt(p);
horiz.joinHorizontal(xp);
currentNode.expand(p, vert, horiz);
downTree();
setState(EXPAND, expandPopupMenu);
}
}
*/
void toggleGrid() {
gridOn = !gridOn;
updateDiagram();
}
void cancelKnot() {
nChosenPoints = 0;
state = BETWEEN_KNOTS;
setPopupMenu(betweenKnotsPopupMenu);
updateDiagram();
statusLabel.setText("between knots");
}
void completeLink() {
System.out.println("in completeLink()");
state = COMPLETE;
if (link != null) {
System.out.println("about to call link.wrapUp()");
link.wrapUp();
System.out.println("after call to link.wrapUp()");
// statusLabel.setText("link completed");
report("<noname>");
}
setPopupMenu(completePopupMenu);
System.out.println("after setting to completePopupMenu");
updateDiagram();
}
void completeKnot() {
System.out.println("in completeKnot state = " + state);
state = BETWEEN_KNOTS;
setPopupMenu(betweenKnotsPopupMenu);
nChosenEdges = 0;
nChosenPoints = 0;
knotEdgeCt = 0;
startPt = null;
lastEdge = null;
selectEdge = null;
statusLabel.setText("between knots");
}
public void confirmPressed() {
System.out.println("state = " + state);
String confirmMsg = "";
switch (state) {
case R1I_CROSSING: case MAC_CROSSING:
case UNLINK_CONFIRM: case ROTATE_CONFIRM: case REVERSE_CONFIRM: case REVERSE_KNOT:
switch (state) {
case R1I_CROSSING:
confirmMsg = "r1i performed"; break;
case MAC_CROSSING:
confirmMsg = "mac performed"; break;
case UNLINK_CONFIRM:
addSeries();
addHistory(reverseOrig, link);
confirmMsg = "unlink performed"; break;
case ROTATE_CONFIRM:
confirmMsg = "rotate performed"; break;
case REVERSE_CONFIRM: case REVERSE_KNOT:
addSeries();
addHistory(reverseOrig, link);
confirmMsg = "reverse performed";
selectEdge = null;
break;
}
popState();
statusLabel.setText(confirmMsg);
break;
case RECT_UNKNOT:
if (rectStage != PRESENT || rectWidth < MIN_LENGTH ||
rectHeight < MIN_LENGTH) {
statusLabel.setText("Rect unknot nonexistent or too small");
return;
}
Point[] pa = new Point[5];
pa[0] = new Point(rectLeft, rectTop);
pa[1] = new Point(rectLeft, rectTop+rectHeight);
pa[2] = new Point(rectLeft+rectWidth, rectTop+rectHeight);
pa[3] = new Point(rectLeft+rectWidth, rectTop);
pa[4] = null;
state = VERTEX;
System.out.println("calling addVertices for RECT_UNKNOT: pa.length = "
+ pa.length);
addVertices(pa);
return;
case CLIP_RECT:
if (rectStage != PRESENT || rectWidth < MIN_LENGTH ||
rectHeight < MIN_LENGTH) {
statusLabel.setText("Rect unknot nonexistent or too small");
return;
}
Point[] pa1 = new Point[2];
pa1[0] = new Point(rectLeft, rectTop);
pa1[1] = new Point(rectLeft+rectWidth, rectTop+rectHeight);
// currentNode.setClipRect(pa1);
rectStage = NONE;
setState(EXPAND, expandPopupMenu);
return;
case CROSSING:
completeLink();
return;
case MULTI_KNT_CONFIRM:
int fileNameLen = multiKntFilename.length();
int seqNum = Integer.parseInt(
multiKntFilename.substring(underlinePos+1,
fileNameLen-4))-1;
multiKntFilename = multiKntFilename.substring(0, underlinePos+1)
+ seqNum + multiKntFilename.substring(fileNameLen-4);
saveCurrentLink(multiKntFilename);
statusLabel.setText("saved in " + multiKntFilename);
setState(MULTI_KNT, multiKntPopupMenu);
return;
default:
statusLabel.setText("not expecting crossings confirmation");
return;
}
updateInfoAndDiagram();
}
/*
void doIterate() {
rectStage = NONE;
int iterIndex = 0;
IterDialog iterDlg = new IterDialog(frame, lastPtLoc.x+20, lastPtLoc.y+20);
if (!iterDlg.okayed()) {
statusLabel.setText("Iterate aborted");
setState(COMPLETE, completePopupMenu);
updateDiagram();
return;
}
if (iterDlg.hfMatrixChosen()) { // makeIterativeMatrix()
makeLeftIterativeMatrix_GP_p8(true, null); // first param is oriented
}
if (iterDlg.klMatrixChosen()) { // makeIterativeMatrix()
makeLeftIterativeMatrix_GP_p8(false, null); // first param is oriented
}
try {
link = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
boolean geometric = iterDlg.geometricChosen();
boolean gauss = iterDlg.gaussChosen();
boolean jenkins = iterDlg.jenkinsChosen();
boolean pl = iterDlg.plChosen();
boolean hfSeries = iterDlg.hfSeriesChosen();
boolean klSeries = iterDlg.klSeriesChosen();
if (gauss || jenkins || geometric || pl) {
int lbound = iterDlg.getLbound();
int ubound = iterDlg.getUbound();
try {
for (iterIndex = lbound; iterIndex <= ubound; iterIndex++)
Iterate.makeKnt(iterIndex, gauss, jenkins, geometric, pl);
statusLabel.setText("ITERATE completed");
}
catch (Exception anyExc) {
statusLabel.setText(iterIndex + ": " + anyExc.getMessage());
}
}
Link hfSeriesLink = null;
Link klSeriesLink = null;
int hfCount = 0, klCount = 0;
int newLeft = 0, newRight = 0;
String kntName = currKntName;
if (currKntName.endsWith(".knt"))
kntName = kntName.substring(0, kntName.length()-4);
try {
if (hfSeries || klSeries) {
newLeft = rectLeft - (3*ITERATE_DX)/5;
newRight = newLeft + ITERATE_DX/5;
}
if (hfSeries) {
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
Iterate.getLeftIterScheme_GG(true, (Hashtable)null, true);
// to get the standard left ends
hfCount = iterDlg.getHfCount();
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
hfSeriesLink = Iterate.createKnt(hfCount, true);
}
if (klSeries) {
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
Iterate.getLeftIterScheme_GG(false, (Hashtable) null, true);
// to get the standard left ends
klCount = iterDlg.getKlCount();
try {
iterLink = new UnitLink(link);
Iterate.checkFitness(iterLink, rectLeft, rectLeft+rectWidth,
ITERATE_DX, ITERATE_GAP, currKntName);
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
klSeriesLink = Iterate.createKnt(klCount, true);
}
if (hfSeries) {
UnitLink hfIterLink = new UnitLink(hfSeriesLink);
Iterate.checkFitness(hfIterLink, newLeft, newRight,
ITERATE_DX/5, ITERATE_GAP, kntName);
savePSLeftBases(kntName+"-"+hfCount, true, (Hashtable) null);
// oriented permuteTable
}
if (klSeries) {
UnitLink klIterLink = new UnitLink(klSeriesLink);
Iterate.checkFitness(hfIterLink, newLeft, newRight,
ITERATE_DX/5, ITERATE_GAP, kntName);
savePSLeftBases(kntName+"-"+klCount, false, (Hashtable) null);
// oriented permuteTable
}
}
catch(Exception anyExc) {
System.out.println(anyExc);
statusLabel.setText("series: " + anyExc.getMessage());
setState(COMPLETE, completePopupMenu);
updateDiagram();
}
}
boolean same(LPoly2[] A, LPoly2[] B) {
if (A.length != B.length) return false;
for (int i = 0; i < A.length; i++)
if (!A[i].equals(B[i])) return false;
return true;
}
static void makeLeftIterativeMatrix_G(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_G(oriented, permuteTable);
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_G(oriented, permuteTable);
try {
PrintWriter pw = Iterate.getOutfile("G" + (GLink.simplifyFlag ? "S" : "")
+ (GLink.wrongFlag ? "W" : "") + "-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_G (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GG(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GG(oriented, permuteTable, false); // use old simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, false); // use old simplify
try {
PrintWriter pw = Iterate.getOutfile("GG" + (GLink.simplifyFlag ? "S" : "")
+ (GLink.wrongFlag ? "W" : "") + "-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GG (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GN(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GG(oriented, permuteTable, true); // use new simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, true); // use new simplify
try {
PrintWriter pw = Iterate.getOutfile("GN-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GN (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GP(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GP(oriented, permuteTable, true); // use new simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, true); // use new simplify
try {
PrintWriter pw = Iterate.getOutfile("GP-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GP (oriented = " + oriented + ") failed");
}
}
static void makeLeftIterativeMatrix_GP_p8(boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftIterScheme_GP_p8(oriented, permuteTable); // use new simplify
Hashtable leftHt = (Hashtable) v.elementAt(0);
LPoly2[][] matx = (LPoly2[][]) v.elementAt(1);
LPoly2[] coeffs = Iterate.getCoeffsVector(leftHt);
LPoly2[] base = Iterate.getLeftBasePolys_GG(oriented, permuteTable, true); // use new simplify
try {
PrintWriter pw = Iterate.getOutfile("GP8" + (GLink.p8aFlag ? "a" : "") + "-", oriented);
pw.println("> with(linalg):");
Iterate.printVector(pw, "C", oriented, coeffs);
Iterate.printMatrix(pw, "M", oriented, matx);
Iterate.printVector(pw, "Y", oriented, base);
pw.close();
}
catch (Exception anyExc) {
System.out.println("makeLeftIterativeMatrix_GP (oriented = " + oriented + ") failed");
}
}
static void compareLeftIterativeMatrix_GP_p8(boolean oriented, Hashtable permuteTable) {
Vector v1 = Iterate.getLeftIterScheme_GP_p8(oriented, permuteTable);
Vector v2 = Iterate.getLeftIterScheme_GG(oriented, permuteTable, true);
LPoly2[][] matx1 = (LPoly2[][]) v1.elementAt(1);
LPoly2[][] matx2 = (LPoly2[][]) v2.elementAt(1);
System.out.println(LPoly2.matrixEquals(matx1, matx2) ? "equal" : "not equal");
}
static void makeLeftBases(boolean oriented) {
Vector v = Iterate.getLeftBases(oriented, (Hashtable) null);
// v.elementAt(0) is a Vector of maps
for (int i = 1, lastI = v.size(); i < lastI; i++) {
Link link = (Link) v.elementAt(i);
System.out.println("#comps = " + link.getNKnots());
BufferedWriter bw;
try {
bw = new BufferedWriter(new FileWriter("H1-" + i + ".knt"));
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(link);
bw.close();
}
catch (Exception anyExc) {
return;
}
}
}
static void savePSLeftBases(String name, boolean oriented, Hashtable permuteTable) {
Vector v = Iterate.getLeftBases(orineted, permuteTable);
int n = v.size();
if (n <= 1) return;
Vector maps = (Vector) v.elementAt(0);
String[] translations = {"80 600 translate", "80 360 translate", "80 120 translate",};
BufferedWriter bw = null;
try {
bw = new BufferedWriter(name + "-" + (oriented ? "hf" : "kl") + "series.ps");
LinkWriter lw = new LinkWriter(bw);
lw.writeLine("%!PS-Adobe-2.0:");
lw.writeLine("%%Creator: dvips 5.58 Copyright 1986, 1994 " +
"Radical Eye Software");
lw.writeLine("%%Title: binstr.dvi");
int perPage = translations.length;
lw.writeLine("%%Pages: " + ((n-1+perPage-1)/perPage));
lw.writeLine("%%PageOrder: Ascend");
lw.writeLine("%%BoundingBox: 0 0 612 792");
lw.writeLine("%%EndComments");
lw.writeLine("%DVIPSCommandLine: dvips binstr");
lw.writeLine("%DVIPSParameters: dpi=600, comments removed");
lw.writeLine("%DVIPSSource: TeX output 1997.08.26:1535");
lw.writeLine("%%BeginProcSet: tex.pro");
lw.writeLine("%%EndProcSet");
lw.writeLine("%%BeginSetup");
int pageNumber = 1;
lw.writeLine("/Times-Roman findfont 18 scalefont setfont");
int transIndex = 0;
for (int i = 1; i < n; i++) {
if (transIndex == 0) {
lw.writeLine("%%Page: " + pageNumber + " " + pageNumber);
pageNumber++;
}
lw.writeLine("gsave");
lw.writeLine(translations[transIndex++]);
lw.writeLine("0.5 0.5 scale");
lw.writeLine("0 " + (boxHt+15) + " moveto (#" + i + " ("
+ Util.getPairing(Util.renumber(
Util.getIntArray((String) maps.elementAt(i-1))))
+ ")) show");
lw.saveRoundPS((Link) v.elementAt(i), boxWd, boxHt, arcRadius, LinkWriter.COLOR);
// bwFlag
lw.writeLine("grestore");
if (transIndex >= translations.length) {
transIndex = 0;
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
}
if (transIndex > 0) {
lw.writeLine("flush");
lw.writeLine("showpage");
lw.writeLine();
}
bw.close();
}
catch (Exception anyExc) {
System.out.println("save PS-series aborted");
System.out.println(anyExc);
return;
}
}
*/
double distance(int x1, int y1, int x2, int y2) {
return Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
public void r1i() {
if (state != COMPLETE && state != EXPAND) {
statusLabel.setText("r1i not allowed on incomplete link");
return;
}
// else if (state == EXPAND && !currentNode.okToSimplify()) {
// statusLabel.setText("r1i not allowed in this link");
// return;
// }
nChosenEdges = 0;
nChosenPoints = 0;
pickMode = EDGES_MODE;
pushState(R1I, pickPopupMenu);
statusLabel.setText("r1i/edges");
}
public void mac() {
System.out.println("in mac() state = " + state);
if (state != COMPLETE && state != EXPAND) {
statusLabel.setText("mac not allowed on incomplete link");
return;
}
// else if (state == EXPAND && !currentNode.okToSimplify()) {
// statusLabel.setText("mac not allowed in this link");
// return;
// }
nChosenEdges = 0;
nChosenPoints = 0;
pickMode = EDGES_MODE;
pushState(MAC, pickPopupMenu);
System.out.println("in mac() after pushState state = " + state);
statusLabel.setText("mac/edges");
}
public void r1d() {
if (state != COMPLETE && state != EXPAND) {
statusLabel.setText("r1d not allowed on incomplete link");
return;
}
// else if (state == EXPAND && !currentNode.okToSimplify()) {
// statusLabel.setText("r1d not allowed in this link");
// return;
// }
else if (selectEdge == null) {
statusLabel.setText("no arc chosen for r1d");
return;
}
try {
link.firstSelectedEdge = selectEdge;
Edge e = selectEdge;
while (e.getOutPt() instanceof NXPt) e = e.getNext();
link.lastSelectedEdge = e;
Link orig = new Link(link);
link.r1d(selectEdge);
link.clearSelectedEdges();
addHistory(orig, link);
}
catch (Exception anyExc) {
link.clearSelectedEdges();
statusLabel.setText(anyExc.getMessage());
return;
}
statusLabel.setText("r1d performed");
selectEdge = null;
updateDiagram();
}
public void edges() {
pickMode = EDGES_MODE;
if (state == MAC) statusLabel.setText("mac/edges");
else statusLabel.setText("r1i/edges");
nChosenPoints = 0;
updateDiagram();
}
public void points() {
if (nChosenEdges == 0) {
statusLabel.setText("must choose edges first");
return;
}
pickMode = POINTS_MODE;
if (state == MAC) statusLabel.setText("mac/points");
else statusLabel.setText("r1i/points");
lastPtLoc = chosenEdge1.getInPt().getLocation();
updateDiagram();
}
/*
public void zigzag() {
// state must be VERTEX
ZZDialog zzDlg = new ZZDialog(frame, lastPtLoc.x+20, lastPtLoc.y+20);
try {
Point[] pa = zzDlg.getPoints(lastPtLoc.x, lastPtLoc.y);
for (int ii = 0; ii < pa.length; ii++) {
if (nChosenPoints < chosenPoints.length) {
lastPtLoc = chosenPoints[nChosenPoints++] = pa[ii];
}
else {
statusLabel.setText("too many points – ignored");
break;
}
}
updateDiagram();
}
catch (Exception anyExc) {
statusLabel.setText("zigzag aborted");
}
}
*/
public void undo() {
if (state == VERTEX) {
nChosenPoints--;
if (nChosenPoints == 0) {
state = BETWEEN_KNOTS;
setPopupMenu(betweenKnotsPopupMenu);
statusLabel.setText("between knots");
}
else lastPtLoc = chosenPoints[nChosenPoints-1];
updateDiagram();
return;
}
if (state != MAC && state != R1I || pickMode != POINTS_MODE) {
statusLabel.setText("can only undo points");
return;
}
if (nChosenPoints > 0) {
nChosenPoints--;
if (nChosenPoints > 0) lastPtLoc = chosenPoints[nChosenPoints-1];
else lastPtLoc = chosenEdge1.getInPt().getLocation();
updateDiagram();
}
}
public void flip() {
if (nChosenPoints > 1) {
Edge temp = chosenEdge1;
chosenEdge1 = chosenEdge2;
chosenEdge2 = temp;
updateDiagram();
}
}
Edge findEdge(Point p) {
return findEdge(link, p);
}
Edge findEdge(Link link, Point p) {
int nKnots = link.getNKnots();
for (int knotId = 0; knotId < nKnots; knotId++) {
Edge e = link.getFirstEdge(knotId);
Edge firstEdge = e;
int x = p.x, y = p.y;
do {
Point p1 = e.getInPt().getLocation();
int x1 = p1.x, y1 = p1.y;
Point p2 = e.getOutPt().getLocation();
int x2 = p2.x, y2 = p2.y;
double edgeLen = distance(x1, y1, x2, y2);
double angle = -e.getTrueAngle()*Math.PI/180;
double dx = (x-x1)*Math.cos(angle) + (y-y1)*Math.sin(-angle);
double dy = (x-x1)*Math.sin(angle) + (y-y1)*Math.cos(angle);
if (0 <= dx && dx <= edgeLen && Math.abs(dy) <= tolerance)
return e;
e = e.getNext();
} while (e != firstEdge);
}
return (Edge) null;
}
void addVertex(Point p) {
pa1[0] = p;
System.out.println("calling addVertices from addVertex");
addVertices(pa1);
}
Point cornerVert(Point p1, Point p2) {
// the corner if we go from p1 to p2, vertically first
return new Point(p1.x, p2.y);
}
Point cornerHoriz(Point p1, Point p2) {
// the corner if we go from p1 to p2, horizontally first
return new Point(p2.x, p1.y);
}
void closeKnot() {
System.out.print("calling addvertices from closeKnot: ");
System.out.println("nChosenPoints = " + nChosenPoints + " knotEdgeCt = " +
knotEdgeCt + " intersectCt = " + intersectCt);
addVertices(chosenPoints, nChosenPoints);
addVertex((Point) null);
state = BETWEEN_KNOTS;
System.out.println("nChosenPoints = " + nChosenPoints + " knotEdgeCt = " +
knotEdgeCt + " intersectCt = " + intersectCt);
}
void closeVert() {
if (state != VERTEX || nChosenPoints < 2) {
statusLabel.setText("no knot to close");
return;
}
if (nChosenPoints < chosenPoints.length) {
chosenPoints[nChosenPoints++] =
cornerVert(lastPtLoc, chosenPoints[0]);
closeKnot();
}
}
void closeHoriz() {
if (state != VERTEX || nChosenPoints < 2) {
statusLabel.setText("no knot to close");
return;
}
if (nChosenPoints < chosenPoints.length) {
chosenPoints[nChosenPoints++] =
cornerHoriz(lastPtLoc, chosenPoints[0]);
closeKnot();
}
}
void addVertices(Point[] pa) {
System.out.println("calling addVertices from addVertices pa.length = " +
pa.length);
addVertices(pa, pa.length);
}
void addVertices(Point[] pa, int nPoints) {
System.out.println("in addVertices(Point[], int): state = " + state +
" nPoints = " + nPoints + " knotEdgeCt = " + knotEdgeCt);
Edge firstNewEdge = null;
int nNewEdges = 0;
boolean closeKnotFlag = false;
for (int kk = 0; kk < nPoints; kk++) {
Point p = pa[kk];
// p is null to close the link
if (p == null) {
closeKnotFlag = true;
if (state != VERTEX) {
statusLabel.setText("vertex not expected");
return;
}
if (knotEdgeCt < 2) {
statusLabel.setText("can't close link yet");
return;
}
newPt = startPt;
p = newPt.getLocation();
}
else newPt = new NXPt(p.x, p.y, link, knotId);
// lastPt = newPt;
if (startPt == null) {
startPt = lastPt = newPt;
knotId = link.newKnot();
continue;
}
if (closeKnotFlag || kk > 0) {
// if (lastPt.equals(startPt)) {
// statusLabel.setText("loop not allowed");
// return;
// }
if (p != null) { outx = p.x; outy = p.y; }
p = lastPt.getLocation();
inx = p.x; iny = p.y;
link.appendEdge(knotId,
newEdge = new Edge(lastPt, newPt, link, knotId));
if (link.firstEdge[knotId] == null) link.firstEdge[knotId] = newEdge;
lastPt.setOutEdge(newEdge);
newPt.setInEdge(newEdge);
lastEdge = newEdge;
if (firstNewEdge == null) firstNewEdge = newEdge;
knotEdgeCt++; linkEdgeCt++; nNewEdges++;
if (linkEdgeCt > linkEdgeMax) {
linkEdgeMax *= 2;
createArrays();
}
}
lastPt = newPt;
}
// if (lastPt.equals(startPt)) {
// System.out.println("lastPt.equals(startPt)");
// statusLabel.setText("loop not allowed");
// return;
// }
if (nPoints > 1 || closeKnotFlag) {
System.out.println("calling handleCrossings nNewEdges = " + nNewEdges);
handleCrossings(firstNewEdge, nNewEdges, link.nKnots-1, false);
}
else System.out.println("skipping handleCrossings");
if (knotEdgeCt > 2 && newPt == startPt)
completeKnot();
updateDiagram();
}
void handleCrossings(Edge firstNewEdge, int nNewEdges, int nOrigKnots,
boolean suppressSelfCrossingsCheck) {
System.out.println("in handleCrossings nNewEdges = " + nNewEdges +
" nOrigKnots = " + nOrigKnots);
Edge newEdge = firstNewEdge;
knotId = newEdge.getKnotId();
int inx, iny, outx, outy;
for (int kk = 0; kk < nNewEdges; kk++) {
Point p = newEdge.getInPt().getLocation();
inx = p.x; iny = p.y;
p = newEdge.getOutPt().getLocation();
outx = p.x; outy = p.y;
Edge nextEdge = newEdge.getNext();
Edge e = link.getFirstEdge(knotId);
int oldIntersectCt = intersectCt;
if (!suppressSelfCrossingsCheck) {
while (e != newEdge) {
System.out.print(e.toString() + " and " + newEdge.toString() + " ");
double t = newEdge.intersect(e);
System.out.println("t = " + t);
if (0 < t && t < 1) {
ta[intersectCt] = t; ea[intersectCt] = e;
intersectCt++;
}
e = e.getNext();
}
}
for (int ii = 0; ii < nOrigKnots; ii++) {
Edge eStart = link.getFirstEdge(ii);
e = eStart;
do {
double t = newEdge.intersect(e);
if (0 < t && t < 1) {
ta[intersectCt] = t;
ea[intersectCt] = e;
intersectCt++;
}
e = e.getNext();
} while (e != eStart);
}
if (intersectCt > oldIntersectCt) {
// sort the ta and ea arrays, by the ta values
for (int ii = intersectCt-1; ii > oldIntersectCt; ii--)
for (int j = oldIntersectCt; j < ii; j++)
if (ta[j] < ta[j+1]) {
double tempT = ta[j];
ta[j] = ta[j+1];
ta[j+1] = tempT;
Edge tempE = ea[j];
ea[j] = ea[j+1];
ea[j+1] = tempE;
}
// assume all crossings are "overcrossings"
for (int ii = oldIntersectCt; ii < intersectCt; ii++) {
double t = ta[ii];
int x = (int) Math.round((1-t)*inx+t*outx);
int y = (int) Math.round((1-t)*iny+t*outy);
xptx[ii] = x; xpty[ii] = y;
XOPt thisMidPt = new XOPt(x, y, link, knotId, ea[ii].getKnotId());
xoa[ii] = thisMidPt;
System.out.println("in handleCrossings ii = " + ii + " xoa[ii] = " +
xoa[ii].encoding());
newEdge.splitEdge(thisMidPt);
ea[ii].splitEdge(thisMidPt.getMate());
linkEdgeCt += 2;
knotEdgeCt++;
if (ea[ii].getKnotId() == knotId) knotEdgeCt++;
newEdge = newEdge.getNext();
}
}
newEdge = nextEdge;
}
}
void handleCrossings(int firstNewKnotId, int nOrigKnots) {
for (int knotId = firstNewKnotId; knotId < link.getNKnots(); knotId++) {
Edge newEdge = link.getFirstEdge(knotId);
int nEdges = link.getNEdges(knotId);
handleCrossings(newEdge, nEdges, nOrigKnots, true);
}
}
boolean addNewEdge(Edge newEdge, Vector pts, Vector edges,
int tolerance) {
edges.addElement(newEdge);
knotEdgeCt = edges.size();
return true;
}
void completeDupKnot(int knotId, int nOrigKnots) {
Edge e = link.getFirstEdge(knotId);
Edge e1 = e;
int nEdges = 0;
do {
nEdges++;
e = e.getNext();
} while (e != e1);
linkEdgeCt += nEdges; knotEdgeCt = nEdges;
if (linkEdgeCt > linkEdgeMax) {
linkEdgeMax *= 2;
createArrays();
}
// load the XOPts of the selfcrossings into the xptx, xpty
// and xoa arrays
XPt p = link.getFirstXPt(knotId);
if (p != null) {
XPt p1 = p;
do {
if (p instanceof XOPt) {
Point loc = p.getLocation();
xptx[intersectCt] = loc.x;
xpty[intersectCt] = loc.y;
xoa[intersectCt] = (XOPt) p;
intersectCt++;
}
p = p.getNext();
} while (p != p1);
}
handleCrossings(link.getFirstEdge(knotId), nEdges, nOrigKnots, true);
}
void completeDupKnot() {
for (int k = nOldKnots; k < link.nKnots; k++)
completeDupKnot(k, nOldKnots);
completeKnot();
updateDiagram();
}
int findCrossing(int x, int y) {
int squaredRadius = radius*radius;
for (int ii = 0; ii < intersectCt; ii++)
if ((x-xptx[ii])*(x-xptx[ii]) + (y-xpty[ii])*(y-xpty[ii]) < squaredRadius)
return ii;
return -1;
}
void toggleCrossing(Point p) {
int crossingIndex = findCrossing(p.x, p.y);
if (crossingIndex >= 0) {
xoa[crossingIndex].toggle();
statusLabel.setText("toggle crossing or confirm");
}
else {
statusLabel.setText("point clicked not a crossing");
}
}
void setAlt(Point p) {
int crossingIndex = findCrossing(p.x, p.y);
if (crossingIndex >= 0) link.setAlt(xoa[crossingIndex]);
}
Point correctPoint(Point p1, Point p2) {
// if the line from p1 to p2 is close to being vertical/horizontal,
// return a Point p3 that makes the line from p3 to p2 exactly
// vertical/horizontal
if (Math.abs(p1.x-p2.x) < RECT_TOLERANCE)
return new Point(p2.x, p1.y);
else if (Math.abs(p1.y-p2.y) < RECT_TOLERANCE)
return new Point(p1.x, p2.y);
else return p1;
}
void tentativeAddHistory(Link orig, int nextState) {
history[nLinks-1] = orig;
addHistory(link);
statusLabel.setText("confirm or cancel");
state = nextState;
setPopupMenu(confirmCancelPopupMenu);
if (nextState != REVERSE_CONFIRM)
selectEdge = null;
updateDiagram();
confirmCancelPopupMenu.show(this, lastClickedPoint.x+20,
lastClickedPoint.y+20);
}
void unlinkKnotNextState(int nextState) {
statusLabel.setText("confirm or cancel");
state = nextState;
setPopupMenu(confirmCancelPopupMenu);
selectEdge = null;
updateDiagram();
confirmCancelPopupMenu.show(this, lastClickedPoint.x + 20,
lastClickedPoint.y + 20);
}
Point gridCorrect(Point p) {
if (!gridOn) return p;
int x = p.x, y = p.y;
x = ((x + GRID_DELTA/2)/GRID_DELTA) * GRID_DELTA;
y = ((y + GRID_DELTA/2)/GRID_DELTA) * GRID_DELTA;
return new Point(x, y);
}
public void mouseClicked(MouseEvent me) {
Pt newPt = null, lastPt = null;
Edge newEdge = null;
Point p = me.getPoint();
Point correctedPoint = gridCorrect(p);
Edge clickedEdge = null;
int nextState = 0;
lastClickedPoint = p;
System.out.println("in mouseClicked last clicked point = " + p.x + "," + p.y);
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
if (state == RECT_UNKNOT) return;
String r3Error = "";
if (p.y < FORBIDDEN_Y) return;
switch (state) {
case BETWEEN_KNOTS:
newPt = new NXPt(correctedPoint.x, correctedPoint.y, null, 0);
if (Geom.nearerThan(newPt, chosenPoints, nChosenPoints, tolerance)) {
statusLabel.setText("too near existing points");
break;
}
startPt = (NXPt) newPt; // for use in close
state = VERTEX;
statusLabel.setText("expecting vertex");
lastPtLoc = chosenPoints[nChosenPoints++] = correctedPoint;
setPopupMenu(vertexPopupMenu);
knotId = link.newKnot();
System.out.println("calling addVertex for BETWEEN_KNOTS");
addVertex(p);
updateInfoAndDiagram();
break;
case VERTEX:
lastPt = newPt;
newPt = new NXPt(correctedPoint.x, correctedPoint.y, null, 0);
newEdge = new Edge(lastPt, newPt, null, 0);
if (!addNewEdge(newEdge, pts, edges, tolerance)) {
statusLabel.setText("too crowded");
return;
}
statusLabel.setText("expecting vertex");
if (nChosenPoints < chosenPoints.length) {
lastPtLoc = chosenPoints[nChosenPoints++] =
gridOn ? correctedPoint : correctPoint(p, lastPtLoc);
updateDiagram();
}
else {
statusLabel.setText("too many points – ignored");
return;
}
break;
case CROSSING:
toggleCrossing(p);
if (altFlag) setAlt(p);
updateDiagram();
break;
/*
case JOIN_VERTICAL: case JOIN_HORIZONTAL:
joinHorV(p);
setState(COMPLETE, completePopupMenu); // will do updateDiagram
break;
case NULLIFY:
nullify(p);
setState(COMPLETE, completePopupMenu); // will do updateDiagram
break;
case EXPAND_CROSSING:
expandCrossing(p);
setState(EXPAND, expandPopupMenu); // will do updateDiagram
break;
*/
case R1I_CROSSING:
link.r1iToggleCrossing();
updateDiagram();
break;
case MAC_CROSSING:
link.macToggleCrossings();
updateDiagram();
break;
case R1I: case MAC:
clickedEdge = null;
if (pickMode == POINTS_MODE) {
if (nChosenPoints < chosenPoints.length) {
lastPtLoc = chosenPoints[nChosenPoints++] =
gridOn ? correctedPoint : correctPoint(p, lastPtLoc);
}
else {
statusLabel.setText("too many points – ignored");
return;
}
}
else if ( (clickedEdge = findEdge(p)) == null ) {
statusLabel.setText("click closer to edge");
return;
}
else {
System.out.println("#chosen edges = " + nChosenEdges);
System.out.println("last clicked edge = " + ((lastClickedEdge == null) ?
"null" : lastClickedEdge.toString())
+ " clicked edge = " + ((clickedEdge == null) ?
"null" : clickedEdge.toString()));
if (nChosenEdges == 0) {
lastClickedEdge = chosenEdge1 = clickedEdge;
nChosenEdges++;
System.out.println("#chosen edges = " + nChosenEdges);
System.out.println("last clicked edge = " + ((lastClickedEdge == null) ?
"null" : lastClickedEdge.toString())
+ " clicked edge = " + ((clickedEdge == null) ?
"null" : clickedEdge.toString()));
}
else if (lastClickedEdge.getKnotId() != clickedEdge.getKnotId()) {
lastClickedEdge = chosenEdge1 = clickedEdge;
nChosenEdges = 1;
}
else if (lastClickedEdge == clickedEdge) {
statusLabel.setText("choose a different edge");
return;
}
else if (nChosenEdges == 1) {
lastClickedEdge = chosenEdge2 = clickedEdge;
nChosenEdges++;
System.out.println("#chosen edges = " + nChosenEdges);
System.out.println("last clicked edge = " + ((lastClickedEdge == null) ?
"null" : lastClickedEdge.toString())
+ " clicked edge = " + ((clickedEdge == null) ?
"null" : clickedEdge.toString()));
}
else { // discard oldest edges if more than two chosen
chosenEdge1 = chosenEdge2;
lastClickedEdge = chosenEdge2 = clickedEdge;
}
}
updateInfoAndDiagram();
break;
case FIRST_EDGE: case MARK_KNOT: case REVERSE_KNOT:
Link cur = link;
selectEdge = findEdge(cur, p);
if (selectEdge == null) {
statusLabel.setText("click closer to edge");
return;
}
if (state == FIRST_EDGE)
cur.setFirstEdge(selectEdge.getKnotId(), selectEdge);
else if (state == REVERSE_KNOT)
link.reverseKnot(selectEdge.getKnotId());
else cur.markKnot(selectEdge.getKnotId());
updateDiagram();
break;
/*
case EXPAND:
Dimension size = getSize();
int px = p.x, py = p.y;
String nodesBar = root.nodesBar();
FontMetrics fm = getFontMetrics(getFont());
int nodesBarWd = fm.stringWidth(nodesBar);
if (NODES_BAR_X <= px && px < NODES_BAR_X + nodesBarWd
&& size.height - NODES_BAR_Y - fm.getAscent() <= py
&& py < size.height - NODES_BAR_Y + fm.getDescent()) {
int ii = 0;
while (NODES_BAR_X + fm.stringWidth(nodesBar.substring(0,ii+1))
< px) ii++;
while (nodesBar.charAt(ii) != ' ') ii--;
int j = nodesBar.indexOf(' ', ii+1);
int k = Integer.parseInt(nodesBar.substring(ii+1, j));
currentNode = root.node(k);
currentNode.reset();
link = currentNode.getCurrentLink();
selectEdge = null;
updateDiagram();
return;
}
// else handle like COMPLETE
*/
case COMPLETE:
selectEdge = findEdge(p);
Edge e = selectEdge;
if (selectEdge == null) return;
while (selectEdge.getInPt() instanceof NXPt) {
selectEdge = selectEdge.getPrev();
if (selectEdge == e) {
statusLabel.setText("no more crossings");
selectEdge = null;
return;
}
}
statusLabel.setText("arc chosen");
updateDiagram();
break;
case UNLINK_KNOT: case ROTATE: // case REVERSE_KNOT
case MULTI_KNT_UNLINK: // case MARK_KNOT
selectEdge = findEdge(p);
if (selectEdge == null) {
statusLabel.setText("click closer to edge");
return;
}
Link orig = new Link(link);
try {
switch (state) {
case UNLINK_KNOT:
link.unlinkKnot(selectEdge.getKnotId());
nextState = UNLINK_CONFIRM;
break;
case MULTI_KNT_UNLINK:
link.unlinkKnot(selectEdge.getKnotId());
nextState = MULTI_KNT_CONFIRM;
break;
case ROTATE:
link.rotate(selectEdge.getKnotId(), degCcw);
nextState = ROTATE_CONFIRM;
break;
}
}
catch (Exception anyExc) {
statusLabel.setText(anyExc.getMessage());
return;
}
if (state != UNLINK_KNOT) tentativeAddHistory(orig, nextState);
else unlinkKnotNextState(nextState);
break;
default:
statusLabel.setText("mode " + modeNames[state] +
": unexpected mouse click");
}
}
public void mouseEntered(MouseEvent me) {
}
public void mouseExited(MouseEvent me) {
}
public void mouseMoved(MouseEvent me) {
}
public void drawRectUnknot() {
Rectangle[] updateClipRegions = new Rectangle[4];
Graphics g = getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawRect(rectLeft, rectTop, rectWidth, rectHeight);
}
public void mousePressed(MouseEvent me) {
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
Point p = me.getPoint();
int x = p.x, y = p.y;
Point correctedPoint = gridCorrect(p);
int cx = correctedPoint.x, cy = correctedPoint.y;
if (y < FORBIDDEN_Y) return;
switch (state) {
case BETWEEN_KNOTS: case EXPAND: case COMPLETE:
if (link == null) link = new Link();
rectLeft = cx; rectTop = cy;
return;
case RECT_UNKNOT: case CLIP_RECT: case DUP_KNOT_CHOOSE: case DUP_KNOT_MOVE:
break;
default:
return;
}
if (state == DUP_KNOT_CHOOSE) {
Edge clickedEdge = findEdge(p);
if (clickedEdge == null) {
statusLabel.setText("click closer to edge");
return;
}
lastDupPoint = correctedPoint;
nOldKnots = link.dupChosenKnot(clickedEdge);
state = DUP_KNOT_MOVE;
Graphics g = offscreen.getGraphics();
link.xorDraw(g, knotId, true);
updateDiagram();
return;
}
if (state == DUP_KNOT_MOVE && lastDupPoint == null) {
p = correctedPoint;
lastDupPoint = p;
return;
}
if (rectStage == PRESENT)
drawRectUnknot(); // clear old rect
rectLeft = cx; rectTop = cy; rectWidth = rectHeight = 1;
rectStage = PRESENT;
drawRectUnknot();
}
public void mouseDragged(MouseEvent me) {
System.out.println("in mouseDragged state = " + state);
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
Point p = me.getPoint();
int x = p.x, y = p.y;
Point correctedPoint = gridCorrect(p);
int cx = correctedPoint.x, cy = correctedPoint.y;
if (y < FORBIDDEN_Y) return;
switch (state) {
case BETWEEN_KNOTS: case EXPAND: case RECT_UNKNOT:
case CLIP_RECT: case DUP_KNOT_MOVE: case COMPLETE: case ITERATE:
break;
default:
return;
}
if (state == DUP_KNOT_MOVE) {
Graphics g = getGraphics();
Graphics og = offscreen.getGraphics();
link.xorDraw(og, nOldKnots, true);
link.moveKnots(nOldKnots, cx-lastDupPoint.x, cy-lastDupPoint.y);
link.xorDraw(og, nOldKnots, true);
lastDupPoint = correctedPoint;
g.drawImage(offscreen, 0, 0, this);
return;
}
// if (state == BETWEEN_KNOTS) {
// state = RECT_UNKNOT; setPopupMenu(confirmCancelPopupMenu);
// statusLabel.setText("rect unknot");
// rectStage = PRESENT;
// // state = RECT_UNKNOT; setPopupMenu(confirmCancelPopupMenu);
// // statusLabel.setText("rect unknot");
// // rectStage = PRESENT;
// }
if (state == BETWEEN_KNOTS) {
setPopupMenu(confirmCancelPopupMenu);
return;
}
else if (state == EXPAND) {
state = CLIP_RECT; setPopupMenu(confirmCancelPopupMenu);
statusLabel.setText("clip rect");
rectStage = PRESENT;
}
else if (state == COMPLETE) {
// state = ITERATE; setPopupMenu(confirmCancelPopupMenu);
// statusLabel.setText("iterate");
// rectStage = PRESENT;
}
else if ((state == RECT_UNKNOT || state == CLIP_RECT || state == ITERATE)
&& rectStage == PRESENT)
drawRectUnknot();
rectWidth = cx-rectLeft; rectHeight = cy-rectTop;
drawRectUnknot();
}
public void mouseReleased(MouseEvent me) {
// if (state == ZIGZAG) return;
if ((me.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) return;
if (state == DUP_KNOT_MOVE) {
completeDupKnot();
updateDiagram();
return;
}
Point p = me.getPoint();
int x = p.x, y = p.y;
Point correctedPoint = gridCorrect(p);
int cx = correctedPoint.x, cy = correctedPoint.y;
if (y < FORBIDDEN_Y || (state != RECT_UNKNOT && state != ITERATE
&& state != EXPAND && state != CLIP_RECT))
return;
if (state == ITERATE) {
// if (!fitForIterate()) {
// setState(COMPLETE, completePopupMenu);
// return;
// }
// try {
// if (currKntName == null) throw new Exception("no name for iterate");
// iterLink = new UnitLink(link);
// Iterate.checkFitness(iterLink, rectLeft, rectLeft + rectWidth,
// ITERATE_DX, ITERATE_GAP, currKntName);
// doIterate();
// return;
// } catch (Exception anyExc) {
// System.out.println(anyExc);
// statusLabel.setText(anyExc.getMessage());
// setState(COMPLETE, completePopupMenu);
return;
// }
}
// confirmCancelPopupMenu.show(this, x+5, y+5);
}
// boolean fitForIterate() {
// int rectRight = rectLeft+rectWidth-1;
// iterLink = new UnitLink(link);
// Vector v = iterLink.getUnfitPts(rectLeft, rectRight, ITERATE_DX);
// if (v.size() != 0) {
// statusLabel(“#unfit points = “ + v.size());
// return false;
// }
// return true;
//}
void drawCross(Graphics g, Color c, Point p) {
Color oldColor = g.getColor();
g.setColor( c );
g.drawLine(p.x-2, p.y, p.x+2, p.y);
g.drawLine(p.x, p.y-2, p.x, p.y+2);
g.setColor(oldColor);
}
void drawThinLine(Graphics g, Color c, Point p1, Point p2) {
Color oldColor = g.getColor();
g.setColor( c );
g.drawLine(p1.x, p1.y, p2.x, p2.y);
g.setColor(oldColor);
}
void drawGrid(Graphics g) {
if (!gridOn) return;
int x = 0, y = 0;
Color oldColor = g.getColor();
g.setColor(Color.cyan.brighter());
g.setXORMode(Color.white);
Dimension size = getSize();
while (x < size.width) {
if (x % (GRID_DELTA*10) != 0) g.drawLine(x, 0, x, size.height-1);
x += GRID_DELTA;
}
while (y < size.height) {
if (y % (GRID_DELTA*10) != 0) g.drawLine(0, y, size.width-1, y);
y += GRID_DELTA;
}
x = y = 0;
g.setColor(Color.cyan.darker());
while (x < size.width) {
g.drawLine(x, 0, x, size.height-1);
x += GRID_DELTA*10;
}
while (y < size.height) {
g.drawLine(0, y, size.width-1, y);
y += GRID_DELTA*10;
}
g.setColor(oldColor);
g.setPaintMode();
}
/*
public void drawBackground(Graphics g) {
if (background == null) return;
g.drawImage(background, 0, 0, this);
}
*/
public void paint(Graphics g) {
System.out.println("in paint state = " + state);
if (link == null) return;
// drawBackground(g);
drawGrid(g);
if (state == TRICOLOR) {
link.tricolorDraw(g);
return;
}
else if (state == SKELETON || state == SIMPLIFY) {
skeletonCopy.draw(g, false);
return;
}
if (state == DUP_KNOT_MOVE) {
g.drawImage(offscreen, 0, 0, this);
return;
}
// System.out.println("in paint, about to call link.draw link to draw:");
// link.print();
// System.out.println("end of link to draw");
link.draw(g, state == VERTEX // || state == BETWEEN_KNOTS
|| state == RECT_UNKNOT);
// in VERTEX or RECT_UNKNOT state, ignore crossings
/*
if (currentNode != null) {
Point[] clipRect = currentNode.clipRect;
if (clipRect != null && clipRect[0].x != 0) { // draw clip rect
Point lowerLeft = new Point(clipRect[0].x, clipRect[1].y);
Point upperRight = new Point(clipRect[1].x, clipRect[0].y);
drawThinLine(g, Color.black, clipRect[0], lowerLeft);
drawThinLine(g, Color.black, clipRect[0], upperRight);
drawThinLine(g, Color.black, clipRect[1], lowerLeft);
drawThinLine(g, Color.black, clipRect[1], upperRight);
}
Dimension size = getSize();
String nodesBar = root.nodesBar();
g.drawString(nodesBar, NODES_BAR_X, pageHeight - NODES_BAR_Y);
FontMetrics fm = getFontMetrics(getFont());
String currentSeqNo = currentNode.seqNo + " ";
int offset = nodesBar.indexOf(currentSeqNo);
g.drawString("^", NODES_BAR_X +
fm.stringWidth(nodesBar.substring(0, offset)),
size.height - NODES_BAR_Y + fm.getHeight());
}
*/
// if (state == JOIN_VERTICAL || state == JOIN_HORIZONTAL ||
// state == NULLIFY || state == EXPAND_CROSSING) {
// link.hiliteCrossings(g, radius);
// }
if (state == CROSSING) {
Color oldColor = g.getColor();
g.setColor(Color.blue);
for (int ii = 0; ii < intersectCt; ii++)
g.drawOval(xptx[ii]-radius, xpty[ii]-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
if ((state == COMPLETE || state == EXPAND) && selectEdge != null) {
Edge e = selectEdge;
e.draw(g, Color.blue, false, link.marked[e.getKnotId()]);
while (e.getOutPt() instanceof NXPt) {
e.getNext();
e.draw(g, Color.blue, false, !link.marked[e.getKnotId()]);
}
}
if ((state == STRAIGHTEN || state == R1I || state == MAC || state == R2I)
&& nChosenEdges != 0) {
chosenEdge1.draw(g, Color.blue, false,
!link.marked[chosenEdge1.getKnotId()]);
if (nChosenEdges > 1) {
Edge e = chosenEdge1;
do {
e = e.getNext();
e.draw(g, Color.blue, false, link.marked[e.getKnotId()]);
} while (e != chosenEdge2);
}
Point p = chosenEdge1.getInPt().getLocation();
Color oldColor = g.getColor();
g.setColor(Color.blue);
g.fillOval(p.x-radius, p.y-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
if ((state == R1I || state == MAC || state == VERTEX)
&& nChosenPoints != 0) {
for (int ii = 0; ii < nChosenPoints; ii++)
drawCross(g, Color.magenta, chosenPoints[ii]);
if (nChosenEdges > 0) drawThinLine(g, Color.magenta,
chosenEdge1.getInPt().getLocation(), chosenPoints[0]);
for (int ii = 0; ii < nChosenPoints-1; ii++)
drawThinLine(g, Color.magenta, chosenPoints[ii], chosenPoints[ii+1]);
}
if (state == R1I_CROSSING) {
Point p = link.getR1iXPtLoc();
Color oldColor = g.getColor();
g.setColor(Color.blue);
g.drawOval(p.x-radius, p.y-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
else if (state == MAC_CROSSING) {
Point[] pa = link.getMacXPtLocArray();
Color oldColor = g.getColor();
g.setColor(Color.blue);
for (int ii = 0; ii < pa.length; ii++)
g.drawOval(pa[ii].x-radius, pa[ii].y-radius, 2*radius, 2*radius);
g.setColor(oldColor);
}
if ((state == RECT_UNKNOT || state == CLIP_RECT || state == ITERATE)
&& rectStage == PRESENT) drawRectUnknot();
}
void updateInfoAndDiagram() {
if (reviewMode) report(seriesName[currentSeries]);
else report(currKntName);
updateDiagram();
}
void updateDiagram() {
System.out.println("in updateDiagram state = " + state);
// update(getGraphics());
if (initializing) {
initializing = false;
update(getGraphics());
// initPopupMenu.show(this, 200, 200);
return;
}
Graphics g = getGraphics();
makeOffscreen();
Graphics og = offscreen.getGraphics();
update(og);
g.drawImage(offscreen, 0, 0, null);
// validate();
}
public void takeThis(Link link) {
this.link = link;
updateDiagram();
}
}
LinkFrame.java:
---------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkFrame extends Frame
implements ActionListener {
Button initButton, confirmButton, closeButton, completeButton;
Button cancelButton;
Button r1dButton, r2dButton, r3Button, straightenButton;
Button macButton, edgesButton, pointsButton, flipButton;
Button r1iButton, r2iButton;
Label statusLabel;
Panel controlPanel, centerPanel;
LinkCanvas lc;
public LinkFrame(String[] args) {
statusLabel = new Label("this area for status and error messages");
centerPanel = new Panel();
centerPanel.setLayout(new BorderLayout());
centerPanel.add("North", statusLabel);
lc = new LinkCanvas(this, new Dimension(600, 500), statusLabel,
new Label(" "));
// status label
centerPanel.add("Center", lc);
add("Center", centerPanel);
pack();
setVisible(true);
try {
Thread.sleep(500);
}
catch (Exception anyExc) {
}
if (args.length != 0) {
String name = args[0];
if (!name.endsWith(".knt")) name += ".knt";
lc.load(name);
}
// lc.showInitPopupMenu();
}
public void setArcRadius(int r) {
lc.setArcRadius(r);
}
public void actionPerformed(ActionEvent e) {
}
public void takeThis(Link link) {
lc.takeThis(link);
}
public static void main(String[] args) {
LinkFrame f = new LinkFrame(args);
// if (args.length > 0) f.setArcRadius(Integer.parseInt(args[0]));
try {
Thread.sleep(100000);
}
catch (Exception anyExc) { }
}
}
LinkReader.java:
----------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkReader {
BufferedReader br;
Link link;
String s = "";
int pos = 0, slen = 0;
Hashtable ht;
public LinkReader(BufferedReader br) {
this.br = br;
}
public int getNLinks() {
try {
return Integer.parseInt(br.readLine());
}
catch (Exception anyExc) {
return 0;
}
}
void getLine() {
try {
s = br.readLine();
}
catch (Exception anyExc) {
s = "";
}
slen = s.length();
pos = 0;
// System.out.println("line from knt file = " + s);
}
int getInt() {
int pos1 = (s + " ").indexOf(' ', pos);
int res = Integer.parseInt(s.substring(pos, pos1));
pos = pos1+1;
return res;
}
String getCode() {
if (pos >= slen) getLine();
int pos1 = s.indexOf('#', pos);
String res = s.substring(pos, pos1+1);
pos = pos1+1;
return res;
}
String getString() {
if (pos > s.length()) return "";
return s.substring(pos);
}
int getSelectedEdgeCode() {
// 0 = not selected 1 = first selected edge 2 = last selected edge
if (pos >= slen) return 0;
char c = s.charAt(pos++);
if (c == 'f') return 1;
else if (c == 'l') return 2;
pos--; return 0;
}
int getFirstEdgeCode() {
// 0 = not first 1 = first
if (pos >= slen) return 0;
char c = s.charAt(pos++);
if (c == 'F') return 1;
pos--; return 0;
}
Pt getPt(int knotId) {
XOPt xOPt = null;
String hashKey = "";
Pt p = null, res = null;
String code = getCode();
// System.out.println("Pt code = " + code);
char type = code.charAt(0);
if (type == 't') {
System.out.println("null Pt");
return (Pt) null;
}
// System.out.print("edge code = " + code.charAt(0));
int comma = code.indexOf(',');
int x = Integer.parseInt(code.substring(1, comma));
// System.out.println(" x = " + x);
// System.out.print("remaining line = " + code.substring(comma+1));
int hashSign = code.indexOf('#', comma+1);
int comma1 = code.indexOf(',', comma+1);
int yEnd = comma1;
if (yEnd < 0) yEnd = hashSign;
else yEnd = Math.min(hashSign, comma1);
// System.out.print(" hashSign at " + hashSign + " second comma at " + comma1
// + " yEnd at " + yEnd);
int y = Integer.parseInt(code.substring(comma+1, yEnd));
// System.out.print(" y = " + y + " ");
int otherKnotId = 0;
if (comma1 > 0)
otherKnotId = Integer.parseInt(code.substring(comma1+1, hashSign));
switch (code.charAt(0)) {
case 'n':
res = new NXPt(x, y, link, knotId);
System.out.println("Pt is " + res.encoding());
return res;
case 'o':
hashKey = "x" + x + "," + y;
p = (Pt) ht.get(hashKey);
if (p != null) {
p.setKnotId(knotId);
System.out.println("Pt is " + p.encoding());
return p;
}
xOPt = new XOPt(x, y, link, knotId, otherKnotId);
ht.put(hashKey, xOPt.getMate());
// System.out.println("Pt is " + xOPt.encoding());
return xOPt;
case 'u':
hashKey = "x" + x + "," + y;
p = (Pt) ht.get(hashKey);
if (p != null) {
p.setKnotId(knotId);
// System.out.println("Pt is " + p.encoding());
return p;
}
xOPt = new XOPt(x, y, link, otherKnotId, knotId);
ht.put(hashKey, xOPt);
// System.out.println("Pt is " + xOPt.getMate().encoding());
return xOPt.getMate();
}
System.out.println("Pt is null");
return (Pt) null;
}
void setSelectedEdge(Link link, Edge e, int selectedEdgeCode) {
switch (selectedEdgeCode) {
case 0:
return;
case 1:
link.firstSelectedEdge = e;
return;
case 2:
link.lastSelectedEdge = e;
return;
}
}
public Link loadLink() {
link = new Link();
ht = new Hashtable();
Pt currentPt = null;
getLine();
link.nKnots = getInt();
link.totalEdges = getInt();
System.out.println("in loadLink: current link #knots = " + link.nKnots +
" #edges = " + link.totalEdges);
getLine();
// System.out.println("nos. of XPts in the knots:");
for (int knotId = 0; knotId < link.nKnots; knotId++) {
int tempNXPt = link.nXPt[knotId] = getInt();
// System.out.print(tempNXPt + " ");
if (tempNXPt < 0) {
link.nXPt[knotId] = (-tempNXPt)/10;
link.marked[knotId] = true;
}
// System.out.println();
}
int selectedEdgeCode = 0, firstEdgeCode = 0;
for (int knotId = 0; knotId < link.nKnots; knotId++) {
// System.out.println("reading knot#" + knotId);
getLine(); // read the line containing #edges in knot
link.nKnotEdges[knotId] = getInt();
// System.out.println("#edges in knot#" + knotId + " = " + link.nKnotEdges[knotId]);
getLine();
Pt startPt = getPt(knotId);
// System.out.println("startPt = " + startPt.encoding());
firstEdgeCode = getFirstEdgeCode();
selectedEdgeCode = getSelectedEdgeCode();
Pt lastPt = getPt(knotId);
Edge startEdge = new Edge(startPt, lastPt, link, knotId);
// System.out.println("startEdge = " + startEdge.toString());
setSelectedEdge(link, startEdge, selectedEdgeCode);
Edge lastEdge = startEdge, currentEdge;
link.firstEdge[knotId] = startEdge;
startPt.setOutEdge(startEdge);
lastPt.setInEdge(startEdge);
for (int i = 2; i < link.nKnotEdges[knotId]; i++ ) {
// while ( (currentPt = getPt(knotId)) != null ) {
// System.out.println("i = " + i + " ");
currentPt = getPt(knotId);
currentEdge = new Edge(lastPt, currentPt, link, knotId);
// System.out.println(currentEdge.toString() + " firstEdgeCode = " + firstEdgeCode);
if (firstEdgeCode > 0) link.firstEdge[knotId] = currentEdge;
setSelectedEdge(link, currentEdge, selectedEdgeCode);
firstEdgeCode = getFirstEdgeCode();
selectedEdgeCode = getSelectedEdgeCode();
lastEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
lastPt.setOutEdge(currentEdge);
currentPt.setInEdge(currentEdge);
lastEdge = currentEdge; lastPt = currentPt;
}
// at this point, we have read all the edges in the knot
currentEdge = new Edge(lastPt, startPt, link, knotId);
if (firstEdgeCode > 0) link.firstEdge[knotId] = currentEdge;
setSelectedEdge(link, currentEdge, selectedEdgeCode);
lastEdge.setNext(currentEdge);
currentEdge.setPrev(lastEdge);
lastPt.setOutEdge(currentEdge);
startPt.setInEdge(currentEdge);
currentEdge.setNext(startEdge);
startEdge.setPrev(currentEdge);
// System.out.println("last edge = " + currentEdge.toString());
}
System.out.println("about to call link.linkXPts");
link.linkXPts();
System.out.println("about to call link.computeTotalCrossings");
link.computeTotalCrossings();
System.out.println("about to return from loadLink");
return link;
}
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("filename expected");
System.exit(0);
}
Link x = null;
try {
BufferedReader br = new BufferedReader(new FileReader(args[0]));
LinkReader lr = new LinkReader(br);
System.out.println("#links in series = " +
Integer.parseInt(br.readLine()));
x = lr.loadLink();
}
catch (Exception anyExc) {
System.out.println(anyExc);
}
System.out.println("finished reading");
x.print();
LinkFrame f = new LinkFrame((String[]) null);
f.takeThis(x);
try {
Thread.sleep(100000);
}
catch (Exception anyExc) { }
}
}
LinkWriter.java:
----------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LinkWriter {
BufferedWriter bw, aw;
static String wrapPath = "currentpoint stroke newpath moveto";
int radius = 3;
int heightUsed = 0, widthUsed = 0, bandHt = 0;
static final int MAX_HEIGHT = 750;
static final int MAX_WIDTH = 600;
static final int VERTICAL_GAP = 40;
static final int HORIZONTAL_GAP = 40;
static final int DX = 0;
static final int DY = 10;
static final int ADJUST = 10;
static final int CIRCLE_RADIUS = 3;
static final int ARROW_DX = 3;
int maxHeight = MAX_HEIGHT;
int maxWidth = MAX_WIDTH;
double scaleFactor = 1.0;
int pageNum = 0;
public static final int ACTUAL_PAGE_HEIGHT = 790;
static final int COLOR = 0;
static final int GREYSCALE = 1;
static final int BLACK = 2;
public LinkWriter(BufferedWriter bw) {
this.bw = bw;
}
public void setPSPageSize(int w, int h) {
maxWidth = w;
maxHeight = h;
}
public void setAuxWriter(BufferedWriter aw) {
this.aw = aw;
}
public void write(String s) {
try {
System.out.println("in write(String) s = " + s);
bw.write(s, 0, s.length());
} catch (Exception anyExc) {
System.out.println(anyExc);
}
}
public void writeLine(String s) {
try {
bw.write(s, 0, s.length());
bw.newLine();
} catch (Exception anyExc) {
}
}
public void writeLine() {
try {
bw.newLine();
} catch (Exception anyExc) {
}
}
public void awWriteLine(String s) {
try {
aw.write(s, 0, s.length());
aw.newLine();
} catch (Exception anyExc) {
}
}
public void saveNLinks(int n) {
writeLine("" + n);
}
void selectedEdgeCode(Pt p, Edge e1, Edge e2) {
Edge e = p.getOutEdge();
if (e == e1) write(" ");
else if (e == e2) write(" ");
}
void firstEdgeCode(Pt p, Edge firstEdge) {
Edge e = p.getOutEdge();
if (e == firstEdge) write("F");
}
public void saveLink(Link link) throws Exception {
System.out.println(link.nKnots + " " + link.totalEdges);
writeLine(link.nKnots + " " + link.totalEdges);
for (int knotId = 0; knotId < link.nKnots; knotId++) {
write("" + link.nXPt[knotId] + " ");
}
writeLine();
for (int knotId = 0; knotId < link.nKnots; knotId++) {
System.out.println("#edges in knot#" + knotId + " = " + link.nKnotEdges[knotId]);
writeLine("" + link.nKnotEdges[knotId]);
System.out.println("knotId = " + knotId);
Edge firstEdge = link.getFirstEdge(knotId);
Pt startPt = firstEdge.getInPt();
while (startPt instanceof XPt)
startPt = startPt.getOutEdge().getOutPt();
System.out.println("found startPt " + startPt.encoding());
Pt pt = startPt;
int ct = 0;
// do {
// System.out.println("ct = " + ct + " pt = " + pt.encoding());
// write(pt.encoding());
// System.out.println("calling firstEdgeCode");
// firstEdgeCode(pt, firstEdge);
// System.out.println("calling selectedEdgeCode");
// selectedEdgeCode(pt, link.firstSelectedEdge,
// link.lastSelectedEdge);
// ct++;
// if (ct % 5 == 0) writeLine();
// bw.flush();
// pt = pt.getOutEdge().getOutPt();
// System.out.println("new pt = " + pt.encoding());
// System.out.println("at loop test pt = " + pt.encoding() + " startPt = "
// + startPt.encoding());
// if (pt == startPt) break;
// } while (true);
for (int i = 0; i < link.nKnotEdges[knotId]; i++) {
System.out.println("ct = " + ct + " pt = " + pt.encoding());
write(pt.encoding());
System.out.println("calling firstEdgeCode");
firstEdgeCode(pt, firstEdge);
System.out.println("calling selectedEdgeCode");
selectedEdgeCode(pt, link.firstSelectedEdge, link.lastSelectedEdge);
ct++;
if (ct % 5 == 0) writeLine();
// bw.flush();
pt = pt.getOutEdge().getOutPt();
System.out.println("new pt = " + pt.encoding());
System.out.println("at loop test pt = " + pt.encoding() + " startPt = "
+ startPt.encoding());
}
System.out.println("after inner loop");
// writeLine("t#");
writeLine();
}
System.out.println("after outer loop");
}
public void saveKnot(Link link, int knotId, int shiftX) {
Edge firstEdge = link.getFirstEdge(knotId);
Pt startPt = firstEdge.getInPt();
while (startPt instanceof XPt)
startPt = startPt.getOutEdge().getOutPt();
Pt pt = startPt;
int ct = 0;
do {
// write(pt.encoding(shiftX));
write(pt.encoding());
ct++;
if (ct % 5 == 0) writeLine();
pt = pt.getOutEdge().getOutPt();
} while (pt != startPt);
writeLine("t#");
}
public void saveSegment(BdyPt startPt, int shiftX, int lastKinkMidX,
int iterate_gap) {
Pt pt = startPt;
int ct = 0;
int lastKinkLeftX = lastKinkMidX - iterate_gap;
do {
int x = pt.x + iterate_gap;
// worry about removing the last kink due to alignment
ct++;
if (lastKinkMidX < 0 || x < lastKinkLeftX)
// write(pt.encoding(shiftX));
write(pt.encoding());
else if (x <= lastKinkMidX) ;
// else write(pt.encoding(shiftX - 2 * iterate_gap));
else write(pt.encoding());
if (ct % 5 == 0) writeLine();
pt = pt.getOutEdge().getOutPt();
} while (!(pt instanceof BdyPt));
if (ct % 5 > 0) writeLine();
}
String lineto(String postscriptCode) {
// return just the lineto part of the code for an edge
int p = postscriptCode.indexOf("moveto");
return postscriptCode.substring(p + 6);
}
public void savePS(Link link, int boxWd, int boxHt, int colorType) {
String[] knotColorStrings = null;
if (colorType == COLOR) knotColorStrings = Link.getKnotColorStrings();
else if (colorType == GREYSCALE) knotColorStrings = Link.getKnotBWStrings();
else {
knotColorStrings = new String[1];
knotColorStrings[0] = Link.getSelectedEdgeColorString();
}
String selectedEdgeColorString = "1 setlinewidth";
Edge firstSelectedEdge = link.firstSelectedEdge;
Edge lastSelectedEdge = link.lastSelectedEdge;
int[] minMaxXY = link.getMinMaxXY();
int minX = minMaxXY[0], maxX = minMaxXY[1],
minY = minMaxXY[2], maxY = minMaxXY[3];
double r1 = ((double) boxWd / (maxX - minX));
double r2 = ((double) boxHt / (maxY - minY));
double r = (r1 < r2) ? r1 : r2;
for (int knotId = 0; knotId < link.nKnots; knotId++) {
writeLine(knotColorStrings[knotId % knotColorStrings.length]);
writeLine("newpath");
int nXPt = link.getNXPt(knotId);
XUPt xUPt = null;
if (nXPt > 0) {
XPt xPt = link.getFirstXPt(knotId);
for (int ii = 0; ii < nXPt; ii++) {
if (xPt instanceof XUPt) {
xUPt = (XUPt) xPt;
break;
}
xPt = xPt.getNext();
}
}
if (xUPt == null) {
boolean twoParts = false;
Edge startEdge = link.getFirstEdge(knotId);
Edge e = startEdge;
if (firstSelectedEdge != null &&
firstSelectedEdge.getKnotId() == knotId) {
startEdge = e = firstSelectedEdge;
twoParts = true;
writeLine(selectedEdgeColorString);
}
writeLine(e.postscriptCode(minX, minY, r, boxHt));
if (e == lastSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
Edge endEdge = startEdge.getPrev();
while ((e = e.getNext()) != endEdge) {
if (e == firstSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
if (e == lastSelectedEdge)
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
}
if (twoParts)
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
else writeLine("closepath");
} else {
Edge e = xUPt.getOutEdge();
Edge startEdge = e;
if (firstSelectedEdge != null && firstSelectedEdge.getKnotId() == knotId) {
e = firstSelectedEdge;
while (!(e.getInPt() instanceof XUPt)) {
e = e.getPrev();
if (e == lastSelectedEdge) writeLine(selectedEdgeColorString);
}
startEdge = e;
}
do {
if (e == firstSelectedEdge)
writeLine(((e == startEdge) ? "" : wrapPath) +
selectedEdgeColorString);
writeLine(e.postscriptCode(minX, minY, r, boxHt));
if (e == lastSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
while (!(e.getOutPt() instanceof XUPt)) {
e = e.getNext();
if (e == firstSelectedEdge)
writeLine(wrapPath + selectedEdgeColorString);
writeLine(lineto(e.postscriptCode(minX, minY, r, boxHt)));
if (e == lastSelectedEdge)
writeLine(wrapPath + knotColorStrings[knotId]);
}
e = e.getNext();
} while (e != startEdge);
}
writeLine("stroke");
writeLine();
}
writeLine();
}
String midpoint(Point[] pa) {
return "" + pa[0].x + " " + pa[1].x + " add 2 div "
+ pa[0].y + " " + pa[1].y + " add 2 div ";
}
String begpoint(Point[] pa) {
return "" + pa[0].x + " " + pa[0].y + " ";
}
String endpoint(Point[] pa) {
return "" + pa[1].x + " " + pa[1].y + " ";
}
void arcto(Point[] pa) {
writeLine("" + pa[0].x + " " + pa[0].y + " "
+ pa[1].x + " " + pa[1].y + " " + radius + " arcto");
}
public void saveRoundPS(Link link, int boxWd, int boxHt, int radius, int colorType) {
this.radius = radius;
int[] minMaxXY = link.getMinMaxXY();
int minX = minMaxXY[0], minY = minMaxXY[1],
maxX = minMaxXY[2], maxY = minMaxXY[3];
double r1 = ((double) boxWd / (maxX - minX));
double r2 = ((double) boxHt / (maxY - minY));
double r = 1.0;
String[] knotColorStrings = null;
if (colorType == COLOR) knotColorStrings = Link.getKnotColorStrings();
else if (colorType == GREYSCALE) knotColorStrings = Link.getKnotBWStrings();
else {
knotColorStrings = new String[1];
knotColorStrings[0] = Link.getSelectedEdgeColorString();
}
Edge startEdge, e;
Point[] pa;
for (int knotId = 0; knotId < link.nKnots; knotId++) {
writeLine(knotColorStrings[knotId % knotColorStrings.length]);
XUPt xUPt = link.getFirstXUPt(knotId);
if (xUPt == null) { // no break
e = startEdge = link.getFirstEdge(knotId);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " moveto");
do {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
} while (e != startEdge);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " lineto");
writeLine("stroke");
} else { // broken by XUPt’s
XUPt p = xUPt;
do {
e = startEdge = p.getOutEdge();
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(begpoint(pa) + " moveto");
while (!(e.getOutPt() instanceof XUPt)) {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
}
writeLine(endpoint(pa) + " lineto");
writeLine("stroke");
p = (XUPt) e.getOutPt();
} while (p != xUPt);
}
writeLine();
}
writeLine();
}
public void saveRoundPS(Link link, int boxWd, int boxHt, int colorType) {
saveRoundPS(link, boxWd, boxHt, radius, colorType);
}
public void newPage() {
heightUsed = VERTICAL_GAP;
widthUsed = HORIZONTAL_GAP / 2;
bandHt = 0;
pageNum = 1;
}
public void wrapUp() {
awWriteLine("" + ((int) (heightUsed * scaleFactor)));
writeLine("stroke");
writeLine("flush");
writeLine("showpage");
writeLine("%]");
}
void displayHeading(String s) {
int len = s.length();
int segBeg = 0, segEnd;
char c = ' ', c1 = ' ';
do {
segEnd = segBeg;
while (segEnd < len) {
c = s.charAt(segEnd);
if (c == '^' || c == '_' || c == '|') break; // | = distant union
segEnd++;
}
if (segEnd > segBeg) {
writeLine("(" + s.substring(segBeg, segEnd) + ") show");
}
if (segEnd >= len) break;
segBeg = ++segEnd;
if (c == '|') writeLine("sqcup");
else { // ^ or _
String op = (c == '^') ? "showsupscr" : "showsubscr";
c1 = (segBeg < len) ? s.charAt(segBeg++) : ' ';
if (c1 != '{') {
writeLine("(" + c1 + ")" + op);
} else {
segEnd = segBeg;
while (segEnd < len && s.charAt(segEnd) != '}')
segEnd++;
writeLine("(" + s.substring(segBeg, segEnd) + ")" + op);
segBeg = segEnd + 1;
}
}
} while (segBeg < len);
}
void drawArrow(Edge e, int minX, int minY, double r, int boxHt) {
double angle = -e.getTrueAngle();
Point[] pa = e.PSEndpoints(minX, minY, r, boxHt);
int x = 0, y = 0;
int dx = pa[1].x - pa[0].x;
int dy = pa[1].y - pa[0].y;
double len = Math.sqrt(dx * dx + dy * dy);
if (len > 5 * ARROW_DX) {
x = (2 * pa[0].x + 3 * pa[1].x) / 5;
y = (2 * pa[0].y + 3 * pa[1].y) / 5;
} else {
x = (pa[0].x + 3 * pa[1].x) / 4;
y = (pa[0].y + 3 * pa[1].y) / 4;
}
writeLine(x + " " + y + " " + ARROW_DX + " " + angle + " arrow");
writeLine("stroke");
}
public void saveTreePSInit(double scaleFactor) {
int normalFontSize = (int) (12 * 0.7 / scaleFactor);
int subscrFontSize = (int) (8 * 0.7 / scaleFactor);
writeLine("/Math findfont fsz scalefont");
writeLine("/normalfont exch def");
writeLine("/sfsz " + subscrFontSize + " def");
writeLine("/Math findfont sfsz scalefont");
writeLine("/subscrfont exch def");
writeLine("");
writeLine("/showsubscr");
writeLine("{");
writeLine(" 0 sfsz 2 div rmoteto");
writeLine(" subscrfont setfont");
writeLine(" show");
writeLine(" normalfont setfont");
writeLine(" 0 sfsz 2 div rmoteto");
writeLine("} def");
writeLine("");
writeLine("/showsupscr");
writeLine("{");
writeLine(" 0 sfsz 2 div rmoveto");
writeLine(" subscrfont setfont");
writeLine(" show");
writeLine(" normalfont setfont");
writeLine(" 0 sfsz 2 div neg rmoveto");
writeLine("} def");
writeLine("");
writeLine("/sqcup");
writeLine("{");
writeLine(" currentlinewidth");
writeLine(" 1 setlinewidth");
writeLine(" fsz 4 div 0 rmoveto");
writeLine(" currentpoint");
writeLine(" 0 fsz 2 div rlineto");
writeLine(" moveto");
writeLine(" fsz 2 div 0 rlineto");
writeLine(" currentpoint");
writeLine(" 0 fsz 2 div rlineto");
writeLine(" moveto");
writeLine(" fsz 4 div 0 rmoveto");
writeLine(" setlinewidth");
writeLine(" def");
writeLine("");
writeLine("/arrow % x y dx angle");
writeLine("{");
writeLine(" aangle exch def");
writeLine(" adx exch def");
writeLine(" gsave");
writeLine(" translate");
writeLine(" aangle rotate");
writeLine(" 0 0 moveto");
writeLine(" adx neg adx neg rlineto");
writeLine(" 0 0 moveto");
writeLine(" adx neg adx rlineto");
writeLine(" stroke");
writeLine(" grestore");
writeLine("} def");
writeLine("%[ 0 " + (ACTUAL_PAGE_HEIGHT - maxHeight)
+ " " + maxWidth + " " + ACTUAL_PAGE_HEIGHT
);
writeLine("%%Page: 1 1");
writeLine("0 " + (ACTUAL_PAGE_HEIGHT - maxHeight) + " translate");
writeLine(scaleFactor + " " + scaleFactor + " scale");
newPage();
}
public void saveTreePS(Link link, Point expandedCrossing,
Point[] clipRect, String heading,
double scaleFactor, boolean showOrientations) {
this.scaleFactor = scaleFactor;
int scaledHeight = (int) (maxHeight / scaleFactor);
int scaledWidth = (int) (maxWidth / scaleFactor);
this.radius = radius;
int[] minMaxXY = link.getMinMaxXY();
int minX = minMaxXY[0], minY = minMaxXY[1],
maxX = minMaxXY[2], maxY = minMaxXY[3];
int boxHt = maxY - minY;
int boxWd = maxX - minX;
int left = 0, right = 0, top = 0, bottom = 0;
if (clipRect != null) {
left = clipRect[0].x;
top = clipRect[0].y;
right = clipRect[1].x;
bottom = clipRect[1].y;
}
if (left < minX) left = minX - ADJUST;
if (right == 0 || right > maxX) right = maxX + ADJUST;
if (top < minY) top = minY - ADJUST;
if (bottom == 0 || bottom > maxY) bottom = maxY - ADJUST;
int clipHt = bottom - top;
int actualHt = (clipHt == 0) ? boxHt : clipHt;
int clipWd = right - left;
int actualWd = (clipWd == 0) ? boxWd : clipWd;
boolean newBand = false;
if (widthUsed + HORIZONTAL_GAP + actualWd > scaledWidth)
newBand = true;
else if (heightUsed + actualHt - bandHt > scaledWidth)
newBand = true;
if (newBand) {
widthUsed = HORIZONTAL_GAP / 2;
if (actualHt + VERTICAL_GAP + heightUsed > scaledHeight) {
// heightUsed = -VERTICAL_GAP/2;
awWriteLine("" + ((int) (heightUsed * scaleFactor)));
heightUsed = 0;
writeLine("stroke");
writeLine("flush");
writeLine("showpage");
pageNum++;
writeLine("%%Page: " + pageNum + " " + pageNum);
writeLine("0 " + (ACTUAL_PAGE_HEIGHT - maxHeight)
+ " translate");
writeLine(scaleFactor + " " + scaleFactor + " scale");
}
bandHt = actualHt;
heightUsed += actualHt + VERTICAL_GAP;
writeLine("gsave");
writeLine((widthUsed + HORIZONTAL_GAP + " "
+ (scaledHeight - heightUsed)) + " translate");
widthUsed += HORIZONTAL_GAP + actualWd;
} else { // continue on same band
if (actualHt > bandHt) {
heightUsed += (actualHt - bandHt);
bandHt = actualHt;
}
writeLine("gsave");
writeLine((widthUsed + HORIZONTAL_GAP) + " "
+ (scaledHeight - heightUsed) + " translate");
widthUsed += HORIZONTAL_GAP + actualWd;
}
writeLine(DX + " " + (bandHt + DY) + " moveto");
displayHeading(heading);
writeLine("stroke");
writeLine("0 0 moveto");
if (clipHt > 0) { // take account of clip rect
writeLine((left - minX) + " neg" + (maxY - bottom) +
" neg translate");
writeLine("newpath");
writeLine("" + (left - minX) + " " + (maxY - bottom) + " moveto");
writeLine("0 " + (bottom - top) + " rlineto");
writeLine((right - left) + " 0 rlineto");
writeLine("0 " + (bottom - top) + " neg rlineto");
writeLine("closepath");
writeLine("clip");
}
writeLine("newpath");
double r = 1.0;
Edge startEdge, e;
Point[] pa;
clipRect[0] = new Point(left, top);
clipRect[1] = new Point(right, bottom);
for (int knotId = 0; knotId < link.nKnots; knotId++) {
if (link.knotOutsideClipRect(knotId, clipRect)) continue;
if (link.marked[knotId]) writeLine("2 setlinewidth");
XUPt xUPt = link.getFirstXUPt(knotId);
if (xUPt == null) { // no break
e = startEdge = link.getFirstEdge(knotId);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " moveto");
do {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
} while (e != startEdge);
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(midpoint(pa) + " lineto");
writeLine("stroke");
} else { // broken by XUPt’s
XUPt p = xUPt;
do {
e = startEdge = p.getOutEdge();
pa = e.PSEndpoints(minX, minY, r, boxHt);
writeLine(begpoint(pa) + " moveto");
while (!(e.getOutPt() instanceof XUPt)) {
e = e.getNext();
pa = e.PSEndpoints(minX, minY, r, boxHt);
arcto(pa);
}
writeLine(endpoint(pa) + " lineto");
writeLine("stroke");
p = (XUPt) e.getOutPt();
} while (p != xUPt);
}
if (showOrientations)
drawArrow(link.getFirstEdge(knotId), minX, minY, r, boxHt);
if (link.marked[knotId]) writeLine("1 setlinewidth");
writeLine();
}
if (expandedCrossing != null) {
XOPt xOPt = link.findXOPt(expandedCrossing);
Point xp = xOPt.getLocation();
writeLine((xp.x - minX) + " " + (boxHt - (xp.y - minY))
+ " " + CIRCLE_RADIUS + " 0 360 arc");
if (showOrientations) {
e = xOPt.getOutEdge();
drawArrow(e, minX, minY, r, boxHt);
e = xOPt.getMate().getOutEdge();
drawArrow(e, minX, minY, r, boxHt);
}
writeLine("stroke grestore");
writeLine();
}
}
public void saveJenkins(Link link) {
link.numberCrossings();
writeLine(link.nKnots + "");
for (int knotId = 0; knotId < link.nKnots; knotId++) {
int n = link.nXPt[knotId];
writeLine(n + "");
XPt p = link.firstXPt[knotId];
for (int ii = 0; ii < n; ii++, p = p.getNext()) {
write(p.getCrossingId() + " " +
((p instanceof XOPt) ? 1 : -1) + " ");
p = p.getNext();
}
writeLine();
}
}
public void saveGauss(Link link) {
link.numberCrossings();
for (int knotId = 0; knotId < link.nKnots; knotId++) {
int n = link.nXPt[knotId];
XPt p = link.firstXPt[knotId];
for (int ii = 0; ii < n; ii++, p = p.getNext()) {
XOPt xOPt = null;
if (p instanceof XOPt) xOPt = (XOPt) p;
else xOPt = (XOPt) p.getMate();
char aboveOrBelow = (p instanceof XOPt) ? 'a' : 'b';
char sign = (link.isRightHanded(xOPt)) ? '+' : '-';
write("" + aboveOrBelow + (1 + p.getCrossingId()) + sign);
}
if (knotId < link.nKnots - 1) write("|");
}
writeLine();
}
public static void main(String[] args) {
if (args.length <= 0) {
System.out.println("filename expected");
System.exit(0);
}
Link x = null;
try {
BufferedReader br = new BufferedReader(new FileReader(args[0]));
LinkReader lr = new LinkReader(br);
System.out.println("#links in series = " + Integer.parseInt(br.readLine()));
x = lr.loadLink();
} catch (Exception anyExc) {
System.out.println(anyExc);
return;
}
System.out.println("finished reading");
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(args[1]));
LinkWriter lw = new LinkWriter(bw);
lw.saveNLinks(1);
lw.saveLink(x);
bw.close();
} catch (Exception anyExc) {
System.out.println(anyExc);
return;
}
}
}
LoadFileDialog.java:
--------------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class LoadFileDialog {
Frame f;
String loadFileName = null;
public LoadFileDialog(Frame f) {
this.f = f;
}
public BufferedReader getLoadFile(String title, String extension)
throws Exception {
FileDialog file = new FileDialog(f, title, FileDialog.LOAD);
file.setFile(extension); // set initial file filter;
file.setVisible(true); // blocks
String curFile = null;
if ( (curFile = file.getFile()) == null )
throw new Exception("cancelled");
System.out.println("curFile = " + curFile);
loadFileName = curFile;
String filename = file.getDirectory() + curFile;
System.out.println("using " + filename);
BufferedReader bw = new BufferedReader(new FileReader(filename));
if (bw == null) System.out.println("open failed");
return bw;
}
public String getLoadFileName() {
return loadFileName;
}
}
MakePopupMenu.java:
-------------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class MakePopupMenu {
public static PopupMenu make(String[] cmds, ActionListener al) {
PopupMenu pm = new PopupMenu();
for (int ii = 0; ii < cmds.length; ii++) {
MenuItem mi = null;
if (cmds[ii].charAt(0) != '(') mi = new MenuItem(cmds[ii]);
else {
Menu me = new Menu(cmds[ii].substring(1));
while (!cmds[++ii].equals(")")) {
mi = new MenuItem(cmds[ii]);
me.add(mi);
mi.addActionListener(al);
}
mi = me;
}
pm.add(mi);
mi.addActionListener(al);
}
return pm;
}
}
NumAnal.java:
-------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class NumAnal {
public static double[][] makeAlexMatx(int[][] codedMatx, int t) {
int n = codedMatx.length;
double[][] a = new double[n][n];
for (int ii = 0; ii < n; ii++)
for (int j = 0; j < n; j++) a[ii][j] = 0;
for (int ii = 0; ii < n; ii++) {
a[ii][codedMatx[ii][0]] = 1-t;
a[ii][codedMatx[ii][1]] = -1;
a[ii][codedMatx[ii][2]] = t;
}
return a;
}
public static double det(double[][] A, int n) {
// calculate determinant of the top n-by-n part of A
// use Gaussian elimination
// destroys A in the process
for (int ii = 0; ii < n; ii++)
for (int j = 0; j < n; j++)
System.out.print(A[ii][j] + " ");
boolean negFlag = false;
for (int ii = 0; ii < n; ii++) {
// pivot if necessary
int iii = ii;
while (iii < n) {
if (A[iii][ii] != 0) break;
iii++;
}
if ( !(iii < n ) ) return 0.0;
if (iii != ii) {
negFlag = !negFlag;
double[] tempRow = A[ii];
A[ii] = A[iii];
A[iii] = tempRow;
}
for (int j = ii+1; j < n; j++) {
// reduce remaining rows
if (A[j][ii] == 0) continue;
double factor = A[j][ii]/A[ii][ii];
A[j][ii] = 0;
for (int k = ii+1; k < n; k++)
A[j][k] -= factor*A[ii][k];
}
}
double res = A[0][0];
for (int ii = 0; ii < n; ii++) res *= A[ii][ii];
if (negFlag) res = -res;
System.out.println(": " + res);
return res;
}
public static double[] newtonInterp(int[][] codedMatx) {
int n = codedMatx.length; // degree = n-1
for (int ii = 0; ii < n; ii++)
System.out.println(codedMatx[ii][0] + " " +
codedMatx[ii][1] + " " +
codedMatx[ii][2]);
// calculate function values at –(n/2), -(n/2)+1, …
int startValue = -(n/2);
double[] f = new double[n];
for (int ii = 0; ii < n; ii++)
f[ii] = Math.round(det(makeAlexMatx(codedMatx, startValue+ii), n-1));
for (int ii = 0; ii < n; ii++)
System.out.print( ((int) f[ii]) + " ");
System.out.println();
// now calculate divided differences
for (int ii = 1; ii < n; ii++)
for (int j = n-1; j >= 1; j--)
f[j] = (f[j]-f[j-1])/ii;
for (int ii = 0; ii < n; ii++)
System.out.print( f[ii] + " " );
System.out.println();
// now calculate the polynomial
double[] a = new double[n];
a[0] = f[n-1];
int d = 0; // current degree
for (int iii = n-2; iii >= 0; iii--) {
int ii = iii + startValue;
// poly  poly*(x-ii)+f[iii]
a[d+1] = a[d];
for (int j = d; j > 0; j--)
a[j] = a[j-1] - ii*a[j];
a[0] = f[iii] - ii*a[0];
d++;
}
return a;
}
public static void main(String[] args) throws Exception {
}
}
NXPt.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class NXPt extends Pt {
public NXPt(int x, int y, Link parentLink, int knotId) {
super(x, y, parentLink, knotId);
}
public NXPt(Pt p) {
super(p);
}
public String getTypeCode() {
return "NXPt";
}
public Pt makeCopy(Hashtable ht, Link parentLink) {
return new NXPt(x, y, parentLink, getKnotId());
}
public String encoding() {
return "n" + x + "," + y + "#";
}
public String encoding(int shiftX) {
return "n" + (x+shiftX) + "," + y + "#";
}
}
Pt.java:
--------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public abstract class Pt {
int x, y;
Edge inEdge, outEdge;
Link parentLink;
int knotId;
static final double SLOPE_TOLERANCE = 0.01;
public Pt(int x, int y, Link parentLink, int knotId) {
this.x = x; this.y = y; this.parentLink = parentLink; this.knotId = knotId;
}
public Pt(Pt p) {
this(p.x, p.y, p.parentLink, p.knotId);
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getKnotId() {
return knotId;
}
public void setKnotId(int knotId) {
this.knotId = knotId;
}
public void setParentLink(Link pl) {
parentLink = pl;
}
public abstract String getTypeCode();
public void setEdges(Edge inEdge, Edge outEdge) {
this.inEdge = inEdge; this.outEdge = outEdge;
}
public void setInEdge(Edge e) {
inEdge = e;
}
public void setOutEdge(Edge e) {
outEdge = e;
}
public Edge getInEdge() {
return inEdge;
}
public Edge getOutEdge() {
return outEdge;
}
public Pt getNextPt() {
return outEdge.getOutPt();
}
public Point getLocation() {
return new Point(x, y);
}
public boolean equals(Object other) {
if (!(other instanceof Pt)) return false;
Pt otherPt = (Pt) other;
return (x == otherPt.x && y == otherPt.y);
}
static boolean collinear(Point p, Point q, Point r) {
int px = p.x, py = p.y;
int qx = q.x, qy = q.y;
int rx = r.x, ry = r.y;
if (px == qx || qx == rx) return px == rx;
double m1 = ((double) (py-qy)/(px-qx));
double m2 = ((double) (qy-ry)/(qx-rx));
return Math.abs(m1-m2) < SLOPE_TOLERANCE;
}
public boolean collinear() {
return collinear(inEdge.getInPt().getLocation(),
getLocation(),
outEdge.getOutPt().getLocation());
}
public void rotate(int midx, int middy, double sin, double cos) {
// rotate the Pt about (midx, middy) thru an angle
// whose sine and cosine are sin and cos
int dx = x - midx, dy = y - middy;
x = (int) Math.round(midx + dx*cos + dy*sin);
y = (int) Math.round(middy - dx*sin + dy*cos);
}
public String toString() {
return getTypeCode() + "(" + x + "," + y + ")";
}
public abstract Pt makeCopy(Hashtable ht, Link parentLink);
public abstract String encoding();
}
SaveFileDialog.java:
--------------------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class SaveFileDialog {
Frame f;
String dialogTitle, fileExtn, filename;
public SaveFileDialog(Frame f, String dialogTitle, String fileExtn) {
this.f = f; this.dialogTitle = dialogTitle; this.fileExtn = fileExtn;
}
public BufferedWriter getSaveFile() throws Exception {
FileDialog file = new FileDialog(f, dialogTitle, FileDialog.SAVE);
file.setFile("*." + fileExtn); // set initial filename filter
file.show();
String curFile;
if ((curFile = file.getFile()) == null)
throw new Exception("cancelled");
filename = file.getDirectory() + curFile;
return new BufferedWriter(new FileWriter(filename));
}
public String getFileName() {
return filename;
}
}
SaveLinkDialog.java:
--------------------
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import java.util.*;
public class SaveLinkDialog extends Dialog implements ActionListener {
Button okButton = new Button("OK"), cancelButton = new Button("Cancel");
boolean okClicked = false;
Checkbox geomCheckbox = new Checkbox();
Checkbox psColorCheckbox = new Checkbox();
Checkbox psGSCheckbox = new Checkbox();
Checkbox psBWCheckbox = new Checkbox();
Checkbox jenkinsCheckbox = new Checkbox();
TextField nameRootTF = new TextField(20);
boolean geomChecked = false, psColorChecked = false, psGSChecked = false, psBWChecked = false, jenkinsChecked = false;
String nameRoot = null;
public Panel makeSaveLinkPanel() {
Panel p = new Panel();
p.setLayout(new BorderLayout());
Panel saveLinkPanel = new Panel();
saveLinkPanel.setLayout(new BorderLayout());
Panel inputPanel = new Panel();
inputPanel.setLayout(new BorderLayout());
Panel selectionPanel = new Panel();
selectionPanel.setLayout(new GridLayout(5, 2));
selectionPanel.add(new Label("Geometric Code"));
selectionPanel.add(geomCheckbox);
selectionPanel.add(new Label("PS Color Code"));
selectionPanel.add(psColorCheckbox);
selectionPanel.add(new Label("PS GreyScale Code"));
selectionPanel.add(psGSCheckbox);
selectionPanel.add(new Label("PS BW Code"));
selectionPanel.add(psBWCheckbox);
selectionPanel.add(new Label("Jenkins Code"));
selectionPanel.add(jenkinsCheckbox);
inputPanel.add(selectionPanel, "North");
Panel nameRootPanel = new Panel();
nameRootPanel.setLayout(new FlowLayout());
nameRootPanel.add(new Label("Name Root"));
nameRootPanel.add(nameRootTF);
inputPanel.add(nameRootPanel, "Center");
Panel okCancelPanel = new Panel();
okCancelPanel.setLayout(new GridLayout(1,2));
okCancelPanel.add(okButton);
okCancelPanel.add(cancelButton);
inputPanel.add(okCancelPanel, "South");
saveLinkPanel.add(inputPanel, "Center");
return saveLinkPanel;
}
public SaveLinkDialog(Frame f, int x, int y) {
super(f, true); // dialog is modal
setTitle("Save Series");
setLayout(new BorderLayout());
add(makeSaveLinkPanel(), "Center");
okButton.addActionListener(this);
cancelButton.addActionListener(this);
pack();
setLocation(x, y);
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == okButton) {
System.out.println("ok clicked");
okClicked = true;
geomChecked = geomCheckbox.getState();
psColorChecked = psColorCheckbox.getState();
psGSChecked = psGSCheckbox.getState();
psBWChecked = psBWCheckbox.getState();
jenkinsChecked = jenkinsCheckbox.getState();
nameRoot = nameRootTF.getText();
}
dispose();
}
public boolean geomChosen() {
return geomChecked;
}
public boolean psColorChosen() {
return psColorChecked;
}
public boolean psGSChosen() {
return psGSChecked;
}
public boolean psBWChosen() {
return psBWChecked;
}
public boolean jenkinsChosen() {
return jenkinsChecked;
}
public String getNameRoot() {
return nameRoot;
}
public boolean okayed() {
return okClicked;
}
public boolean cancelled() {
return !okClicked;
}
public static void main(String[] args) {
Frame f = new Frame("SaveLinkDialog Test");
f.setSize(800, 600);
f.setVisible(true);
SaveLinkDialog saveLinkDlg = new SaveLinkDialog(f, 200, 150);
if (saveLinkDlg.okayed()) {
if (saveLinkDlg.geomChosen()) System.out.print("geom ");
if (saveLinkDlg.psColorChosen()) System.out.print("PS-Color ");
if (saveLinkDlg.psGSChosen()) System.out.print("PS-GreyScale ");
if (saveLinkDlg.psBWChosen()) System.out.print("PS-BW ");
if (saveLinkDlg.jenkinsChosen()) System.out.print("jenkins ");
System.out.println(saveLinkDlg.getNameRoot());
}
else {
System.out.println("Cancelled");
}
System.exit(0);
}
}
Split.java:
-----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class Split {
static void writeLine(BufferedWriter bw, String s) {
try {
bw.write(s, 0, s.length());
bw.newLine();
}
catch (Exception anyExc) {
}
}
static void writeLine(BufferedWriter bw) {
try {
bw.newLine();
}
catch (Exception anyExc) {
}
}
public static void split(String name) throws Exception {
BufferedReader br= null;
BufferedReader ar = null;
BufferedWriter bw = null;
String s = "";
Vector preamble = new Vector();
int[] bb = new int[4];
try {
br = new BufferedReader(new FileReader(name + ".ps"));
ar = new BufferedReader(new FileReader(name + ".aux"));
s = br.readLine();
while (!s.startsWith("%[")) {
preamble.addElement(s);
s = br.readLine();
}
s += " ";
int p1 = s.indexOf(' '), p2 = 0;
for (int ii = 0; ii < 4; ii++) {
p2 = s.indexOf(' ', p1+1);
bb[ii] = Integer.parseInt(s.substring(p1+1, p2));
p1 = p2;
}
s = br.readLine();
while (!s.startsWith("%]")) { // must be %%Page: n n
p1 = s.indexOf(' ');
p2 = s.indexOf(' ', p1+1);
bw = new BufferedWriter(new FileWriter(name + "-" +
s.substring(p1+1,p2) + ".ps"));
String auxLine = ar.readLine();
int pgHt = Integer.parseInt(auxLine);
writeLine(bw, "%%BoundingBox:"
+ " " + bb[0]
+ " " + (bb[1]-pgHt)
+ " " + bb[2]
+ " " + bb[3]);
for (int ii = 0; ii < preamble.size(); ii++)
writeLine(bw, (String) preamble.elementAt(ii));
s = br.readLine();
while (!s.startsWith("%%Page") && !s.startsWith("%]")) {
writeLine(bw, s);
s = br.readLine();
}
bw.close();
}
br.close();
ar.close();
}
catch (Exception anyExc) {
System.out.println(anyExc);
System.exit(0);
}
}
public static void main(String[] args) throws Exception {
String[] names = {
"xder", "bder", "dder", "eder", "ider", "bbder",
};
if (args.length > 0) names = args;
for (int ii = 0; ii < names.length; ii++) {
split(names[ii]);
}
}
}
Util.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class Util {
public static void leftRotate1(int[] x, int n) {
// left rotate first n elements of x, by 1 position
int temp = x[0];
for (int ii = 0; ii < n - 1; ii++) x[ii] = x[ii + 1];
x[n - 1] = temp;
}
public static void leftRotate1(double[] x, int n) {
// left rotate first n elements of x, by 1 position
double temp = x[0];
for (int ii = 0; ii < n - 1; ii++) x[ii] = x[ii + 1];
x[n - 1] = temp;
}
public static String getLastComponent(String s) {
System.out.println("in getLastComponent s = " + s);
int lastSeparatorPos = s.lastIndexOf(File.separator);
if (lastSeparatorPos >= 0) s = s.substring(lastSeparatorPos+1);
System.out.println("returning " + s);
return s;
}
}
XOPt.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class XOPt extends XPt {
int crossingId;
public XOPt(int x, int y, Link parentLink, int knotId, int mateKnotId) {
super(x, y, parentLink, knotId);
mate = new XUPt(x, y, parentLink, mateKnotId, knotId, this);
}
public Pt makeNew(Hashtable ht, String hashKey, Link parentLink) {
XOPt pt = new XOPt(x, y, parentLink, getKnotId(), getMate().getKnotId());
ht.put(hashKey, pt.getMate());
return pt;
}
public int getCrossingId() {
return crossingId;
}
public String getTypeCode() {
return "XOPt<" + x + "," + y + "," + mate.getKnotId() + ">";
}
public String getEncoding() {
return encoding();
}
public String encoding() {
return "o" + x + "," + y + "," + mate.getKnotId() + "#";
}
}
XPt.java:
---------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public abstract class XPt extends Pt {
XPt mate;
XPt prev, next;
public XPt(int x, int y, Link parentLink, int knotId) {
super(x, y, parentLink, knotId);
}
public XPt getMate() {
return mate;
}
public void toggle() {
Edge myInEdge = inEdge, myOutEdge = outEdge, mateInEdge = mate.inEdge,
mateOutEdge = mate.outEdge;
XPt myPrev = prev, myNext = next, matePrev = mate.prev, mateNext = mate.next;
int myKnotId = knotId, mateKnotId = mate.getKnotId();
myInEdge.setOutPt(mate);
myOutEdge.setInPt(mate);
mateInEdge.setOutPt(this);
mateOutEdge.setInPt(this);
inEdge = mateInEdge;
outEdge = mateOutEdge;
mate.inEdge = myInEdge;
mate.outEdge = myOutEdge;
knotId = mateKnotId;
mate.setKnotId(myKnotId);
}
public String getTypeCode() {
return "XPt";
}
public XPt getPrev() {
return prev;
}
public XPt getNext() {
return next;
}
public void setPrev(XPt xpt) {
prev = xpt;
}
public void setNext(XPt xpt) {
next = xpt;
}
public abstract int getCrossingId();
public abstract Pt makeNew(Hashtable ht, String hashKey, Link parentLink);
public Pt makeCopy(Hashtable ht, Link parentLink) {
String s = getHashKey();
Pt pt = (Pt) ht.get(s);
if (pt != null) return pt;
return makeNew(ht, s, parentLink);
}
public String getHashKey() {
return "XPt(" + x + "," + y + ")";
}
}
XUPt.java:
----------
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.net.URL;
public class XUPt extends XPt {
public XUPt(int x, int y, Link parentLink, int knotId, int mateKnotId, XOPt mate) {
super(x, y, parentLink, knotId);
this.mate = mate;
}
public Pt makeNew(Hashtable ht, String hashKey, Link parentLink) {
XOPt pt = new XOPt(x, y, parentLink, getKnotId(), getMate().getKnotId());
ht.put(hashKey, pt);
return pt.getMate();
}
public int getCrossingId() {
return mate.getCrossingId();
}
public String getTypeCode() {
return "XUPt<" + x + "," + y + "," + mate.getKnotId() + ">";
}
public String encoding() {
return "u" + x + "," + y + "," + mate.getKnotId() + "#";
}
public String getEncoding() {
return encoding();
}
}
eg5.txt:
--------
This is a log of the console output from the run. The main program is
LinkFrame. The problem occurs inside the method copyLinkXPts in the
program Link. Only the last four lines or so are relevant: they show
exactly what happened in the execution of the for loop body.
in paint state = 1
in mouseClicked last clicked point = 182,269
in actionPerformed
cmd = load
curFile = eg5.knt
using D:\Alex230816\eg5.knt
in getLastComponent s = eg5.knt
returning eg5.knt
loading from: eg5.knt
#links in file = 1
in loadLink: current link #knots = 2 #edges = 12
Pt is n200,100#
Pt is n200,200#
Pt is n300,200#
Pt is n300,100#
Pt is n250,150#
Pt is n250,250#
Pt is n350,250#
Pt is n350,150#
Pt is o300,150,0#
about to call link.linkXPts
#edges in knot#0 = 6
after do-while loop
first XPt = o250,200,1#
#edges in knot#0 = 6
in loop i = 0 e = (XOPt<250,200,1>(250,200) to NXPt(300,200)) p = n300,200# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(300,200) to XUPt<300,150,1>(300,150))
in loop i = 1 e = (NXPt(300,200) to XUPt<300,150,1>(300,150)) p = u300,150,1# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (XUPt<300,150,1>(300,150) to NXPt(300,100))
in loop i = 2 e = (XUPt<300,150,1>(300,150) to NXPt(300,100)) p = n300,100# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(300,100) to NXPt(200,100))
in loop i = 3 e = (NXPt(300,100) to NXPt(200,100)) p = n200,100# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(200,100) to NXPt(200,200))
in loop i = 4 e = (NXPt(200,100) to NXPt(200,200)) p = n200,200# knotFirstEdge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
new e = (NXPt(200,200) to XOPt<250,200,1>(250,200))
#XPts in knot#0 = 2
#edges in knot#1 = 6
after do-while loop
first XPt = o300,150,0#
#edges in knot#1 = 6
in loop i = 0 e = (XOPt<300,150,0>(300,150) to NXPt(250,150)) p = n250,150# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(250,150) to XUPt<250,200,0>(250,200))
in loop i = 1 e = (NXPt(250,150) to XUPt<250,200,0>(250,200)) p = u250,200,0# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (XUPt<250,200,0>(250,200) to NXPt(250,250))
in loop i = 2 e = (XUPt<250,200,0>(250,200) to NXPt(250,250)) p = n250,250# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(250,250) to NXPt(350,250))
in loop i = 3 e = (NXPt(250,250) to NXPt(350,250)) p = n350,250# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(350,250) to NXPt(350,150))
in loop i = 4 e = (NXPt(350,250) to NXPt(350,150)) p = n350,150# knotFirstEdge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
new e = (NXPt(350,150) to XOPt<300,150,0>(300,150))
#XPts in knot#1 = 2
about to call link.computeTotalCrossings
about to return from loadLink
finished loading from file lastLoadName = eg5.knt
about to call report
in updateDiagram state = 4
in paint state = 4
at end of loadFromFile state = 4
returned from loadFromFile
in mouseDragged state = 4
in mouseDragged state = 4
in actionPerformed
cmd = mac
in mac() state = 4
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mac() after pushState state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in actionPerformed
cmd = edges
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 251,177
#chosen edges = 0
last clicked edge = null clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200))
#chosen edges = 1
last clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200)) clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200))
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 249,225
#chosen edges = 1
last clicked edge = (NXPt(250,150) to XUPt<250,200,0>(250,200)) clicked edge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
#chosen edges = 2
last clicked edge = (XUPt<250,200,0>(250,200) to NXPt(250,250)) clicked edge = (XUPt<250,200,0>(250,200) to NXPt(250,250))
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in mouseDragged state = 10
in actionPerformed
cmd = points
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 220,151
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 220,263
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseDragged state = 10
in actionPerformed
cmd = undo
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 220,251
in updateDiagram state = 10
in paint state = 10
in paint state = 10
in mouseClicked last clicked point = 269,356
in actionPerformed
cmd = complete
in completePressed state = 10
in completePressed() state is MAC #chosen edges = 2
about to construct copy of link
in Link constructor with Link arg
orig:
knot #0:
NXPt(200,200) to XOPt<250,200,1>(250,200)
XOPt<250,200,1>(250,200) to NXPt(300,200)
NXPt(300,200) to XUPt<300,150,1>(300,150)
XUPt<300,150,1>(300,150) to NXPt(300,100)
NXPt(300,100) to NXPt(200,100)
NXPt(200,100) to NXPt(200,200)
knot #1:
XUPt<250,200,0>(250,200) to NXPt(250,250)
NXPt(250,250) to NXPt(350,250)
NXPt(350,250) to NXPt(350,150)
NXPt(350,150) to XOPt<300,150,0>(300,150)
XOPt<300,150,0>(300,150) to NXPt(250,150)
NXPt(250,150) to XUPt<250,200,0>(250,200)
end of orig
knotId = 0 first edge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
start pt = n200,200# last pt = o250,200,1# start edge = (NXPt(200,200) to XOPt<250,200,1>(250,200))
before while loop nXPt[0] = 2
e = (XOPt<250,200,1>(250,200) to NXPt(300,200))
current edge = (XOPt<250,200,1>(250,200) to NXPt(300,200))
e = (NXPt(300,200) to XUPt<300,150,1>(300,150))
current edge = (NXPt(300,200) to XUPt<300,150,0>(300,150))
e = (XUPt<300,150,1>(300,150) to NXPt(300,100))
current edge = (XUPt<300,150,0>(300,150) to NXPt(300,100))
e = (NXPt(300,100) to NXPt(200,100))
current edge = (NXPt(300,100) to NXPt(200,100))
#XPts in knot#0 = 2
about to call copyLinkXPts
in copyLinkXPts #XPts = 2
i = 1
after assignment to pp
after setNext
---------- END SOURCE ----------