import java.awt.*; import java.applet.*; import java.lang.Double; import java.lang.Math; import java.util.Vector;public class ElliFit extends Applet { public void init() { setLayout(new BorderLayout()); CurvePanel dp = new CurvePanel(); add("Center", dp); add("South",new CurveControls(dp)); add("North",new CurveControls2(dp)); } public boolean handleEvent(Event e) { switch (e.id) { case Event.WINDOW_DESTROY: System.exit(0); return true; default: return false; } } public static void main(String args[]) { Frame f = new Frame("ElliFIt"); ElliFit curve = new ElliFit(); curve.init(); curve.start(); f.add("Center", curve); f.show(); } } class ControlPoint extends Object { public int x; public int y; public static final int PT_SIZE = 2; public ControlPoint(int a, int b) { x = a; y = b; } public boolean within(int a, int b) { if (a >= x - PT_SIZE && b >= y - PT_SIZE && a <= x + PT_SIZE && b <= y + PT_SIZE) return true; else return false; } }class CurvePanel extends Panel { public static final int BOOKSTEIN = 0; public static final int TAUBIN = 1; public static final int FPF = 2; private int mode = BOOKSTEIN; public static final int ADD = 0; public static final int MOVE = 1; public static final int DELETE = 2; private int action = ADD; private int i; public String warn_taub_str = "Sorry! Taubin method not yet implemented."; private Vector points = new Vector(16,4); // If a control point is being moved, this is the index into the list // of the moving point. Otherwise it contains -1 private int moving_point; private int precision; private static double BooksteinConstraint[][] = new double[7][7]; private static double FPFConstraint[][] = new double[7][7]; private static double TaubinConstraint[][] = new double[7][7]; public CurvePanel() { setBackground(Color.red); } private void initConstraint() { // INitialize Constraint matrices // Here Initialization $$$ }
public void setAction(int action) { // Change the action type switch (action) { case ADD: case MOVE: case DELETE: this.action = action; break; default: throw new IllegalArgumentException(); } } public void setCurveType(int mode) { // Change the curve display type switch (mode) { case BOOKSTEIN: case TAUBIN: case FPF: this.mode = mode; break; default: throw new IllegalArgumentException(); } } public void clearPoints() { points.removeAllElements(); } private int findPoint(int a, int b) { // Scan the list of control points to find out which (if any) point // contains the coordinates: a,b. // If a point is found, return the point's index, otherwise return -1 int max = points.size(); for(int i = 0; i < max; i++) { ControlPoint pnt = (ControlPoint)points.elementAt(i); if (pnt.within(a,b)) { return i; } } return -1; } public boolean handleEvent(Event e) { switch (e.id) { case Event.MOUSE_DOWN: // How we handle a MOUSE_DOWN depends on the action mode switch (action) { case ADD: // Add a new control point at the specified location ControlPoint pnt; points.addElement(pnt = new ControlPoint(e.x, e.y)); repaint(); break; case MOVE: // Attempt to select the point at the location specified. // If there is no point at the location, findPoint returns // -1 (i.e. there is no point to be moved) moving_point = findPoint(e.x, e.y); break; case DELETE: // Delete a point if one has been clicked int delete_pt = findPoint(e.x, e.y); if(delete_pt >= 0) { points.removeElementAt(delete_pt); repaint(); } break; default: throw new IllegalArgumentException(); } return true; case Event.MOUSE_UP: // We only care about MOUSE_UP's if we've been moving a control // point. If so, drop the control point. if (moving_point >=0) { moving_point = -1; repaint(); } return true; case Event.MOUSE_DRAG: // We only care about MOUSE_DRAG's while we are moving a control // point. Otherwise, do nothing. if (moving_point >=0) { ControlPoint pnt = (ControlPoint) points.elementAt(moving_point); pnt.x = e.x; pnt.y = e.y; repaint(); } return true; case Event.WINDOW_DESTROY: System.exit(0); return true; default: return false; } } private void multMatrix(double m[][], double g[][], double mg[][]) { // This function performs the meat of the calculations for the // curve plotting. Note that it is not a matrix multiplier in the // pure sense. The first matrix is the curve matrix (each curve type // has its own matrix), and the second matrix is the geometry matrix // (defined by the control points). The result is returned in the // third matrix. // First clear the return array for(int i=0; i<4; i++) for(int j=0; j<2; j++) mg[i][j]=0; // Perform the matrix math for(int i=0; i<4; i++) for(int j=0; j<2; j++) for(int k=0; k<4; k++) mg[i][j]=mg[i][j] + (m[i][k] * g[k][j]); } private void ROTATE(double a[][], int i, int j, int k, int l, double tau, double s) { double g,h; g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau); a[k][l]=h+s*(g-h*tau); }
private void jacobi(double a[][], int n, double d[] , double v[][], int nrot) { int j,iq,ip,i; double tresh,theta,tau,t,sm,s,h,g,c; double b[] = new double[n+1]; double z[] = new double[n+1];
for (ip=1;ip<=n;ip++) { for (iq=1;iq<=n;iq++) v[ip][iq]=0.0; v[ip][ip]=1.0; } for (ip=1;ip<=n;ip++) { b[ip]=d[ip]=a[ip][ip]; z[ip]=0.0; } nrot=0; for (i=1;i<=50;i++) { sm=0.0; for (ip=1;ip<=n-1;ip++) { for (iq=ip+1;iq<=n;iq++) sm += Math.abs(a[ip][iq]); } if (sm == 0.0) { /* free_vector(z,1,n); free_vector(b,1,n); */ return; } if (i < 4) tresh=0.2*sm/(n*n); else tresh=0.0; for (ip=1;ip<=n-1;ip++) { for (iq=ip+1;iq<=n;iq++) { g=100.0*Math.abs(a[ip][iq]); if (i > 4 && Math.abs(d[ip])+g == Math.abs(d[ip]) && Math.abs(d[iq])+g == Math.abs(d[iq])) a[ip][iq]=0.0; else if (Math.abs(a[ip][iq]) > tresh) { h=d[iq]-d[ip]; if (Math.abs(h)+g == Math.abs(h)) t=(a[ip][iq])/h; else { theta=0.5*h/(a[ip][iq]); t=1.0/(Math.abs(theta)+Math.sqrt(1.0+theta*theta)); if (theta < 0.0) t = -t; } c=1.0/Math.sqrt(1+t*t); s=t*c; tau=s/(1.0+c); h=t*a[ip][iq]; z[ip] -= h; z[iq] += h; d[ip] -= h; d[iq] += h; a[ip][iq]=0.0; for (j=1;j<=ip-1;j++) { ROTATE(a,j,ip,j,iq,tau,s); } for (j=ip+1;j<=iq-1;j++) { ROTATE(a,ip,j,j,iq,tau,s); } for (j=iq+1;j<=n;j++) { ROTATE(a,ip,j,iq,j,tau,s); } for (j=1;j<=n;j++) { ROTATE(v,j,ip,j,iq,tau,s); } ++nrot; } } } for (ip=1;ip<=n;ip++) { b[ip] += z[ip]; d[ip]=b[ip]; z[ip]=0.0; } } //printf("Too many iterations in routine JACOBI"); }
// Perform the Cholesky decomposition // Return the lower triangular L such that L*L'=A private void choldc(double a[][], int n, double l[][]) { int i,j,k; double sum; double p[] = new double[n+1];
for (i=1; i<=n; i++) { for (j=i; j<=n; j++) { for (sum=a[i][j],k=i-1;k>=1;k--) sum -= a[i][k]*a[j][k]; if (i == j) { if (sum<=0.0) // printf("\nA is not poitive definite!"); {} else p[i]=Math.sqrt(sum); } else { a[j][i]=sum/p[i]; } } } for (i=1; i<=n; i++) for (j=i; j<=n; j++) if (i==j) l[i][i] = p[i]; else { l[j][i]=a[j][i]; l[i][j]=0.0; } } /********************************************************************/ /** Calcola la inversa della matrice B mettendo il risultato **/ /** in InvB . Il metodo usato per l'inversione e' quello di **/ /** Gauss-Jordan. N e' l'ordine della matrice . **/ /** ritorna 0 se l'inversione corretta altrimenti ritorna **/ /** SINGULAR . **/ /********************************************************************/ int inverse(double TB[][], double InvB[][], int N) { int k,i,j,p,q; double mult; double D,temp; double maxpivot; int npivot; double B[][] = new double [N+1][N+2]; double A[][] = new double [N+1][2*N+2]; double C[][] = new double [N+1][N+1]; double eps = 10e-20;
for (k=1;k<=N;k++) { for (j=1;j<=N+1;j++) A[k][j]=B[k][j]; for (j=N+2;j<=2*N+1;j++) A[k][j]=(float)0; A[k][k-1+N+2]=(float)1; } for (k=1;k<=N;k++) { maxpivot=Math.abs((double)A[k][k]); npivot=k; for (i=k;i<=N;i++) if (maxpivot<Math.abs((double)A[i][k])) { maxpivot=Math.abs((double)A[i][k]); npivot=i; } if (maxpivot>=eps) { if (npivot!=k) for (j=k;j<=2*N+1;j++) { temp=A[npivot][j]; A[npivot][j]=A[k][j]; A[k][j]=temp; } ; D=A[k][k]; for (j=2*N+1;j>=k;j--) A[k][j]=A[k][j]/D; for (i=1;i<=N;i++) { if (i!=k) { mult=A[i][k]; for (j=2*N+1;j>=k;j--) A[i][j]=A[i][j]-mult*A[k][j] ; } } } else { // printf("\n The matrix may be singular !!") ; return(-1); }; } /** Copia il risultato nella matrice InvB ***/ for (k=1,p=1;k<=N;k++,p++) for (j=N+2,q=1;j<=2*N+1;j++,q++) InvB[p][q]=A[k][j]; return(0); } /* End of INVERSE */
private void AperB(double _A[][], double _B[][], double _res[][], int _righA, int _colA, int _righB, int _colB) { int p,q,l; for (p=1;p<=_righA;p++) for (q=1;q<=_colB;q++) { _res[p][q]=0.0; for (l=1;l<=_colA;l++) _res[p][q]=_res[p][q]+_A[p][l]*_B[l][q]; } } private void A_TperB(double _A[][], double _B[][], double _res[][], int _righA, int _colA, int _righB, int _colB) { int p,q,l; for (p=1;p<=_colA;p++) for (q=1;q<=_colB;q++) { _res[p][q]=0.0; for (l=1;l<=_righA;l++) _res[p][q]=_res[p][q]+_A[l][p]*_B[l][q]; } }
// Perform the Cholesky decomposition // Return the lower triangular L such that L*L'=A private void choldc(double a[][], int n, double l[][]) { int i,j,k; double sum; double p[] = new double[n+1];
for (i=1; i<=n; i++) { for (j=i; j<=n; j++) { for (sum=a[i][j],k=i-1;k>=1;k--) sum -= a[i][k]*a[j][k]; if (i == j) { if (sum<=0.0) // printf("\nA is not poitive definite!"); {} else p[i]=Math.sqrt(sum); } else { a[j][i]=sum/p[i]; } } } for (i=1; i<=n; i++) for (j=i; j<=n; j++) if (i==j) l[i][i] = p[i]; else { l[j][i]=a[j][i]; l[i][j]=0.0; } } /********************************************************************/ /** Calcola la inversa della matrice B mettendo il risultato **/ /** in InvB . Il metodo usato per l'inversione e' quello di **/ /** Gauss-Jordan. N e' l'ordine della matrice . **/ /** ritorna 0 se l'inversione corretta altrimenti ritorna **/ /** SINGULAR . **/ /********************************************************************/ int inverse(double TB[][], double InvB[][], int N) { int k,i,j,p,q; double mult; double D,temp; double maxpivot; int npivot; double B[][] = new double [N+1][N+2]; double A[][] = new double [N+1][2*N+2]; double C[][] = new double [N+1][N+1]; double eps = 10e-20;
for (k=1;k<=N;k++) { for (j=1;j<=N+1;j++) A[k][j]=B[k][j]; for (j=N+2;j<=2*N+1;j++) A[k][j]=(float)0; A[k][k-1+N+2]=(float)1; } for (k=1;k<=N;k++) { maxpivot=Math.abs((double)A[k][k]); npivot=k; for (i=k;i<=N;i++) if (maxpivot<Math.abs((double)A[i][k])) { maxpivot=Math.abs((double)A[i][k]); npivot=i; } if (maxpivot>=eps) { if (npivot!=k) for (j=k;j<=2*N+1;j++) { temp=A[npivot][j]; A[npivot][j]=A[k][j]; A[k][j]=temp; } ; D=A[k][k]; for (j=2*N+1;j>=k;j--) A[k][j]=A[k][j]/D; for (i=1;i<=N;i++) { if (i!=k) { mult=A[i][k]; for (j=2*N+1;j>=k;j--) A[i][j]=A[i][j]-mult*A[k][j] ; } } } else { // printf("\n The matrix may be singular !!") ; return(-1); }; } /** Copia il risultato nella matrice InvB ***/ for (k=1,p=1;k<=N;k++,p++) for (j=N+2,q=1;j<=2*N+1;j++,q++) InvB[p][q]=A[k][j]; return(0); } /* End of INVERSE */
private void AperB(double _A[][], double _B[][], double _res[][], int _righA, int _colA, int _righB, int _colB) { int p,q,l; for (p=1;p<=_righA;p++) for (q=1;q<=_colB;q++) { _res[p][q]=0.0; for (l=1;l<=_colA;l++) _res[p][q]=_res[p][q]+_A[p][l]*_B[l][q]; } } private void A_TperB(double _A[][], double _B[][], double _res[][], int _righA, int _colA, int _righB, int _colB) { int p,q,l; for (p=1;p<=_colA;p++) for (q=1;q<=_colB;q++) { _res[p][q]=0.0; for (l=1;l<=_righA;l++) _res[p][q]=_res[p][q]+_A[l][p]*_B[l][q]; } }
private void AperB_T(double _A[][], double _B[][], double _res[][], int _righA, int _colA, int _righB, int _colB) { int p,q,l; for (p=1;p<=_colA;p++) for (q=1;q<=_colB;q++) { _res[p][q]=0.0; for (l=1;l<=_righA;l++) _res[p][q]=_res[p][q]+_A[p][l]*_B[q][l]; } } public void pv(double v[], java.lang.String str) { System.out.println("------------" + str + "--------------"); System.out.println(" " + v[1] + " " + v[2] + " " + v[3] + " " + v[4] + " " + v[5] + " " + v[6] ); System.out.println("------------------------------------------"); }
AperB(Ai,b,Aib,2,2,2,1); A_TperB(b,Aib,r1,2,1,2,1); r1[1][1] = r1[1][1] - 4*Ao; AperB(Ai,u,Aiu,2,2,2,npts); for (i=1; i<=2; i++) for (j=1; j<=npts; j++) uAiu[i][j] = u[i][j] * Aiu[i][j]; for (j=1; j<=npts; j++) { if ( (kk=(r1[1][1] / (uAiu[1][j]+uAiu[2][j]))) >= 0.0) lambda[j] = Math.sqrt(kk); else lambda[j] = -1.0; } // Builds up B and L for (j=1; j<=npts; j++) L[1][j] = L[2][j] = lambda[j]; for (j=1; j<=npts; j++) { B[1][j] = b[1][1]; B[2][j] = b[2][1]; }
for (j=1; j<=npts; j++) { ss1[1][j] = 0.5 * ( L[1][j] * u[1][j] - B[1][j]); ss1[2][j] = 0.5 * ( L[2][j] * u[2][j] - B[2][j]); ss2[1][j] = 0.5 * ( -L[1][j] * u[1][j] - B[1][j]); ss2[2][j] = 0.5 * ( -L[2][j] * u[2][j] - B[2][j]); } AperB(Ai,ss1,Xpos,2,2,2,npts); AperB(Ai,ss2,Xneg,2,2,2,npts); for (j=1; j<=npts; j++) { if (lambda[j]==-1.0) { points[1][j] = -1.0; points[2][j] = -1.0; points[1][j+npts] = -1.0; points[2][j+npts] = -1.0; } else { points[1][j] = Xpos[1][j]; points[2][j] = Xpos[2][j]; points[1][j+npts] = Xneg[1][j]; points[2][j+npts] = Xneg[2][j]; } } } public void paint(Graphics g) { int np = points.size(); // number of points double D[][] = new double[np+1][7]; double S[][] = new double[7][7]; double Const[][] = new double[7][7]; double temp[][] = new double [7][7]; double L[][] = new double [7][7]; double C[][] = new double [7][7]; double invL[][] = new double [7][7]; double d[] = new double [7]; double V[][] = new double [7][7]; double sol[][] = new double [7][7]; double tx,ty; int nrot=0; int npts=50; double XY[][] = new double[3][npts+1]; double pvec[] = new double[7]; g.setColor(getForeground()); g.setPaintMode(); // draw a border around the canvas g.drawRect(0,0, size().width-1, size().height-1); // draw the control points for (int i=0; i < np; i++) { ControlPoint p = (ControlPoint)points.elementAt(i); g.drawOval(p.x-p.PT_SIZE, p.y-p.PT_SIZE, p.PT_SIZE*2, p.PT_SIZE*2); //g.drawString(String.valueOf(i),p.x+p.PT_SIZE,p.y-p.PT_SIZE); }
switch (mode) { case(FPF): //System.out.println("FPF mode"); Const[1][3]=-2; Const[2][2]=1; Const[3][1]=-2; break; case(TAUBIN): g.drawString(warn_taub_str,size().width/18 , size().height/18 ); break; case(BOOKSTEIN): //System.out.println("BOOK mode"); Const[1][1]=2; Const[2][2]=1; Const[3][3]=2; } if (np<6) return; // Now first fill design matrix for (int i=1; i <= np; i++) { tx = ((ControlPoint)points.elementAt(i-1)).x; ty = ((ControlPoint)points.elementAt(i-1)).y; D[i][1] = tx*tx; D[i][2] = tx*ty; D[i][3] = ty*ty; D[i][4] = tx; D[i][5] = ty; D[i][6] = 1.0; }
//pm(Const,"Constraint"); // Now compute scatter matrix S A_TperB(D,D,S,np,6,np,6); //pm(S,"Scatter");
choldc(S,6,L); //pm(L,"Cholesky");
inverse(L,invL,6); //pm(invL,"inverse");
AperB_T(Const,invL,temp,6,6,6,6); AperB(invL,temp,C,6,6,6,6); //pm(C,"The C matrix");
jacobi(C,6,d,V,nrot); //pm(V,"The Eigenvectors"); /* OK */ //pv(d,"The eigevalues");
A_TperB(invL,V,sol,6,6,6,6); //pm(sol,"The GEV solution unnormalized"); /* SOl */ // Now normalize them for (int j=1;j<=6;j++) /* Scan columns */ { double mod = 0.0; for (int i=1;i<=6;i++) mod += sol[i][j]*sol[i][j]; for (int i=1;i<=6;i++) sol[i][j] /= Math.sqrt(mod); } //pm(sol,"The GEV solution"); /* SOl */
double zero=10e-20; double minev=10e+20; int solind=0; switch (mode) { case(BOOKSTEIN): // smallest eigenvalue for (i=1; i<=6; i++) if (d[i]<minev && Math.abs(d[i])>zero) solind = i; break; case(FPF): for (i=1; i<=6; i++) if (d[i]<0 && Math.abs(d[i])>zero) solind = i; } // Now fetch the right solution for (int j=1;j<=6;j++) pvec[j] = sol[j][solind]; //pv(pvec,"the solution"); // ...and plot it draw_conic(pvec,npts,XY); for (int i=1; i<npts; i++) { if (XY[1][i]==-1 || XY[1][i+1]==-1 ) continue; else if (i<npts) g.drawLine((int)XY[1][i],(int)XY[2][i],(int)XY[1][i+1],(int)XY[2][i+1] ); else g.drawLine((int)XY[1][i],(int)XY[2][i],(int)XY[1][1],(int)XY[2][1] ); } } }class CurveControls extends Panel { CurvePanel target; Checkbox cb_add; Checkbox cb_move; Checkbox cb_delete; String st_add_label = "Add Points"; String st_move_label = "Move Points"; String st_delete_label = "Delete Points"; public CurveControls(CurvePanel target) { this.target = target; setLayout(new FlowLayout(FlowLayout.CENTER)); setBackground(Color.lightGray); Button clear = new Button("Clear"); add("West",clear); CheckboxGroup action_group = new CheckboxGroup(); add(cb_add = new Checkbox(st_add_label, action_group, true)); add(cb_move = new Checkbox(st_move_label, action_group, false)); add(cb_delete = new Checkbox(st_delete_label, action_group, false)); } public void paint(Graphics g) { Rectangle r = bounds(); g.setColor(Color.lightGray); g.draw3DRect(0, 0, r.width, r.height, false); } public boolean action(Event e, Object arg) { if (e.target instanceof Checkbox) { String cbox = ((Checkbox)(e.target)).getLabel(); if (cbox.equals(st_add_label)) { target.setAction(CurvePanel.ADD); } else if (cbox.equals(st_move_label)) { target.setAction(CurvePanel.MOVE); } else if (cbox.equals(st_delete_label)) { target.setAction(CurvePanel.DELETE); } } else if (e.target instanceof Button) { String button = ((Button)(e.target)).getLabel(); if (button.equals("Clear")) { target.clearPoints(); // After clearing the control points, put the user back into // ADD mode, since none of the other modes make any sense. cb_add.setState(true); cb_delete.setState(false); cb_move.setState(false); target.setAction(CurvePanel.ADD); target.repaint(); } } return true; } }class CurveControls2 extends Panel { CurvePanel target; Checkbox cb_hermite; Checkbox cb_bezier; Checkbox cb_bspline; String st_book_label = "Bookstein"; String st_taubin_label = "Taubin"; String st_fpf_label = "Ellipse-specific"; Scrollbar scroll; Label precision_display; public CurveControls2(CurvePanel target) { this.target = target; setLayout(new FlowLayout(1)); CheckboxGroup type_group = new CheckboxGroup(); add(cb_hermite = new Checkbox(st_book_label, type_group, true)); add(cb_bezier = new Checkbox(st_taubin_label, type_group, false)); // add(cb_bezier = new Checkbox("foo", type_group, false)); add(cb_bspline = new Checkbox(st_fpf_label, type_group, false)); // Set up the scrollbar: Value 15, Page 5, Min 2, Max 40 //add(scroll = new Scrollbar(Scrollbar.HORIZONTAL, 15, 5, 2, 40)); //target.setPrecision(scroll.getValue()); //add(precision_display = new Label("Precision: "+ // String.valueOf(scroll.getValue()),Label.LEFT)); } public void paint(Graphics g) { Rectangle r = bounds(); g.setColor(Color.lightGray); g.draw3DRect(0, 0, r.width, r.height, false); } public boolean handleEvent(Event e) { switch (e.id) { case Event.SCROLL_LINE_DOWN: case Event.SCROLL_LINE_UP: case Event.SCROLL_PAGE_DOWN: case Event.SCROLL_PAGE_UP: target.repaint(); return true; case Event.ACTION_EVENT: // Handle other action events if (e.target instanceof Checkbox) { String cbox = ((Checkbox)(e.target)).getLabel(); if (cbox.equals(st_book_label)) { target.setCurveType(CurvePanel.BOOKSTEIN); } else if (cbox.equals(st_taubin_label)) { // system.out.println("------------------------------------------"); // g.drawString("Taubin not implemented",e.x+5,e.y-5); // System.out.println("Taubin algorithm not yet implemented!"); target.setCurveType(CurvePanel.TAUBIN); } else if (cbox.equals(st_fpf_label)) { target.setCurveType(CurvePanel.FPF); } } target.repaint(); return(true); default: return(false); } } }
import java.applet.*;
import java.lang.Double;
import java.lang.Math;
import java.util.Vector;public class ElliFit extends Applet {
public void init() {
setLayout(new BorderLayout());
CurvePanel dp = new CurvePanel();
add("Center", dp);
add("South",new CurveControls(dp));
add("North",new CurveControls2(dp));
} public boolean handleEvent(Event e) {
switch (e.id) {
case Event.WINDOW_DESTROY:
System.exit(0);
return true;
default:
return false;
}
} public static void main(String args[]) {
Frame f = new Frame("ElliFIt");
ElliFit curve = new ElliFit();
curve.init();
curve.start(); f.add("Center", curve);
f.show();
}
}
class ControlPoint extends Object {
public int x;
public int y;
public static final int PT_SIZE = 2; public ControlPoint(int a, int b) {
x = a;
y = b;
} public boolean within(int a, int b) {
if (a >= x - PT_SIZE &&
b >= y - PT_SIZE &&
a <= x + PT_SIZE &&
b <= y + PT_SIZE)
return true;
else
return false;
}
}class CurvePanel extends Panel {
public static final int BOOKSTEIN = 0;
public static final int TAUBIN = 1;
public static final int FPF = 2;
private int mode = BOOKSTEIN; public static final int ADD = 0;
public static final int MOVE = 1;
public static final int DELETE = 2;
private int action = ADD;
private int i; public String warn_taub_str = "Sorry! Taubin method not yet implemented."; private Vector points = new Vector(16,4); // If a control point is being moved, this is the index into the list
// of the moving point. Otherwise it contains -1
private int moving_point;
private int precision;
private static double BooksteinConstraint[][] = new double[7][7];
private static double FPFConstraint[][] = new double[7][7];
private static double TaubinConstraint[][] = new double[7][7]; public CurvePanel() {
setBackground(Color.red);
} private void initConstraint() {
// INitialize Constraint matrices
// Here Initialization $$$ }
public void setAction(int action) {
// Change the action type
switch (action) {
case ADD:
case MOVE:
case DELETE:
this.action = action;
break;
default:
throw new IllegalArgumentException();
}
} public void setCurveType(int mode) {
// Change the curve display type
switch (mode) {
case BOOKSTEIN:
case TAUBIN:
case FPF:
this.mode = mode;
break;
default:
throw new IllegalArgumentException();
}
} public void clearPoints() {
points.removeAllElements();
} private int findPoint(int a, int b) {
// Scan the list of control points to find out which (if any) point
// contains the coordinates: a,b.
// If a point is found, return the point's index, otherwise return -1
int max = points.size(); for(int i = 0; i < max; i++) {
ControlPoint pnt = (ControlPoint)points.elementAt(i);
if (pnt.within(a,b)) {
return i;
}
}
return -1;
} public boolean handleEvent(Event e) {
switch (e.id) {
case Event.MOUSE_DOWN:
// How we handle a MOUSE_DOWN depends on the action mode
switch (action) {
case ADD:
// Add a new control point at the specified location
ControlPoint pnt;
points.addElement(pnt = new ControlPoint(e.x, e.y));
repaint();
break;
case MOVE:
// Attempt to select the point at the location specified.
// If there is no point at the location, findPoint returns
// -1 (i.e. there is no point to be moved)
moving_point = findPoint(e.x, e.y);
break;
case DELETE:
// Delete a point if one has been clicked
int delete_pt = findPoint(e.x, e.y);
if(delete_pt >= 0) {
points.removeElementAt(delete_pt);
repaint();
}
break;
default:
throw new IllegalArgumentException();
}
return true;
case Event.MOUSE_UP:
// We only care about MOUSE_UP's if we've been moving a control
// point. If so, drop the control point.
if (moving_point >=0) {
moving_point = -1;
repaint();
}
return true;
case Event.MOUSE_DRAG:
// We only care about MOUSE_DRAG's while we are moving a control
// point. Otherwise, do nothing.
if (moving_point >=0) {
ControlPoint pnt = (ControlPoint) points.elementAt(moving_point);
pnt.x = e.x;
pnt.y = e.y;
repaint();
}
return true;
case Event.WINDOW_DESTROY:
System.exit(0);
return true;
default:
return false;
}
} private void multMatrix(double m[][], double g[][], double mg[][]) {
// This function performs the meat of the calculations for the
// curve plotting. Note that it is not a matrix multiplier in the
// pure sense. The first matrix is the curve matrix (each curve type
// has its own matrix), and the second matrix is the geometry matrix
// (defined by the control points). The result is returned in the
// third matrix. // First clear the return array
for(int i=0; i<4; i++)
for(int j=0; j<2; j++)
mg[i][j]=0; // Perform the matrix math
for(int i=0; i<4; i++)
for(int j=0; j<2; j++)
for(int k=0; k<4; k++)
mg[i][j]=mg[i][j] + (m[i][k] * g[k][j]);
}
private void ROTATE(double a[][], int i, int j, int k, int l, double tau, double s)
{
double g,h;
g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);
a[k][l]=h+s*(g-h*tau);
}
private void jacobi(double a[][], int n, double d[] , double v[][], int nrot)
{
int j,iq,ip,i;
double tresh,theta,tau,t,sm,s,h,g,c; double b[] = new double[n+1];
double z[] = new double[n+1];
for (ip=1;ip<=n;ip++) {
for (iq=1;iq<=n;iq++) v[ip][iq]=0.0;
v[ip][ip]=1.0;
}
for (ip=1;ip<=n;ip++) {
b[ip]=d[ip]=a[ip][ip];
z[ip]=0.0;
}
nrot=0;
for (i=1;i<=50;i++) {
sm=0.0;
for (ip=1;ip<=n-1;ip++) {
for (iq=ip+1;iq<=n;iq++)
sm += Math.abs(a[ip][iq]);
}
if (sm == 0.0) {
/* free_vector(z,1,n);
free_vector(b,1,n); */
return;
}
if (i < 4)
tresh=0.2*sm/(n*n);
else
tresh=0.0;
for (ip=1;ip<=n-1;ip++) {
for (iq=ip+1;iq<=n;iq++) {
g=100.0*Math.abs(a[ip][iq]);
if (i > 4 && Math.abs(d[ip])+g == Math.abs(d[ip])
&& Math.abs(d[iq])+g == Math.abs(d[iq]))
a[ip][iq]=0.0;
else if (Math.abs(a[ip][iq]) > tresh) {
h=d[iq]-d[ip];
if (Math.abs(h)+g == Math.abs(h))
t=(a[ip][iq])/h;
else {
theta=0.5*h/(a[ip][iq]);
t=1.0/(Math.abs(theta)+Math.sqrt(1.0+theta*theta));
if (theta < 0.0) t = -t;
}
c=1.0/Math.sqrt(1+t*t);
s=t*c;
tau=s/(1.0+c);
h=t*a[ip][iq];
z[ip] -= h;
z[iq] += h;
d[ip] -= h;
d[iq] += h;
a[ip][iq]=0.0;
for (j=1;j<=ip-1;j++) {
ROTATE(a,j,ip,j,iq,tau,s);
}
for (j=ip+1;j<=iq-1;j++) {
ROTATE(a,ip,j,j,iq,tau,s);
}
for (j=iq+1;j<=n;j++) {
ROTATE(a,ip,j,iq,j,tau,s);
}
for (j=1;j<=n;j++) {
ROTATE(v,j,ip,j,iq,tau,s);
}
++nrot;
}
}
}
for (ip=1;ip<=n;ip++) {
b[ip] += z[ip];
d[ip]=b[ip];
z[ip]=0.0;
}
}
//printf("Too many iterations in routine JACOBI");
}
// Return the lower triangular L such that L*L'=A
private void choldc(double a[][], int n, double l[][])
{
int i,j,k;
double sum;
double p[] = new double[n+1];
for (i=1; i<=n; i++) {
for (j=i; j<=n; j++) {
for (sum=a[i][j],k=i-1;k>=1;k--) sum -= a[i][k]*a[j][k];
if (i == j) {
if (sum<=0.0)
// printf("\nA is not poitive definite!");
{}
else
p[i]=Math.sqrt(sum); }
else
{
a[j][i]=sum/p[i];
}
}
}
for (i=1; i<=n; i++)
for (j=i; j<=n; j++)
if (i==j)
l[i][i] = p[i];
else
{
l[j][i]=a[j][i];
l[i][j]=0.0;
}
}
/********************************************************************/
/** Calcola la inversa della matrice B mettendo il risultato **/
/** in InvB . Il metodo usato per l'inversione e' quello di **/
/** Gauss-Jordan. N e' l'ordine della matrice . **/
/** ritorna 0 se l'inversione corretta altrimenti ritorna **/
/** SINGULAR . **/
/********************************************************************/
int inverse(double TB[][], double InvB[][], int N) {
int k,i,j,p,q;
double mult;
double D,temp;
double maxpivot;
int npivot;
double B[][] = new double [N+1][N+2];
double A[][] = new double [N+1][2*N+2];
double C[][] = new double [N+1][N+1];
double eps = 10e-20;
for(k=1;k<=N;k++)
for(j=1;j<=N;j++)
B[k][j]=TB[k][j];
for (k=1;k<=N;k++)
{
for (j=1;j<=N+1;j++)
A[k][j]=B[k][j];
for (j=N+2;j<=2*N+1;j++)
A[k][j]=(float)0;
A[k][k-1+N+2]=(float)1;
}
for (k=1;k<=N;k++)
{
maxpivot=Math.abs((double)A[k][k]);
npivot=k;
for (i=k;i<=N;i++)
if (maxpivot<Math.abs((double)A[i][k]))
{
maxpivot=Math.abs((double)A[i][k]);
npivot=i;
}
if (maxpivot>=eps)
{ if (npivot!=k)
for (j=k;j<=2*N+1;j++)
{
temp=A[npivot][j];
A[npivot][j]=A[k][j];
A[k][j]=temp;
} ;
D=A[k][k];
for (j=2*N+1;j>=k;j--)
A[k][j]=A[k][j]/D;
for (i=1;i<=N;i++)
{
if (i!=k)
{
mult=A[i][k];
for (j=2*N+1;j>=k;j--)
A[i][j]=A[i][j]-mult*A[k][j] ;
}
}
}
else
{ // printf("\n The matrix may be singular !!") ;
return(-1);
};
}
/** Copia il risultato nella matrice InvB ***/
for (k=1,p=1;k<=N;k++,p++)
for (j=N+2,q=1;j<=2*N+1;j++,q++)
InvB[p][q]=A[k][j];
return(0);
} /* End of INVERSE */
private void AperB(double _A[][], double _B[][], double _res[][],
int _righA, int _colA, int _righB, int _colB) {
int p,q,l;
for (p=1;p<=_righA;p++)
for (q=1;q<=_colB;q++)
{ _res[p][q]=0.0;
for (l=1;l<=_colA;l++)
_res[p][q]=_res[p][q]+_A[p][l]*_B[l][q];
}
} private void A_TperB(double _A[][], double _B[][], double _res[][],
int _righA, int _colA, int _righB, int _colB) {
int p,q,l;
for (p=1;p<=_colA;p++)
for (q=1;q<=_colB;q++)
{ _res[p][q]=0.0;
for (l=1;l<=_righA;l++)
_res[p][q]=_res[p][q]+_A[l][p]*_B[l][q];
}
}
// Return the lower triangular L such that L*L'=A
private void choldc(double a[][], int n, double l[][])
{
int i,j,k;
double sum;
double p[] = new double[n+1];
for (i=1; i<=n; i++) {
for (j=i; j<=n; j++) {
for (sum=a[i][j],k=i-1;k>=1;k--) sum -= a[i][k]*a[j][k];
if (i == j) {
if (sum<=0.0)
// printf("\nA is not poitive definite!");
{}
else
p[i]=Math.sqrt(sum); }
else
{
a[j][i]=sum/p[i];
}
}
}
for (i=1; i<=n; i++)
for (j=i; j<=n; j++)
if (i==j)
l[i][i] = p[i];
else
{
l[j][i]=a[j][i];
l[i][j]=0.0;
}
}
/********************************************************************/
/** Calcola la inversa della matrice B mettendo il risultato **/
/** in InvB . Il metodo usato per l'inversione e' quello di **/
/** Gauss-Jordan. N e' l'ordine della matrice . **/
/** ritorna 0 se l'inversione corretta altrimenti ritorna **/
/** SINGULAR . **/
/********************************************************************/
int inverse(double TB[][], double InvB[][], int N) {
int k,i,j,p,q;
double mult;
double D,temp;
double maxpivot;
int npivot;
double B[][] = new double [N+1][N+2];
double A[][] = new double [N+1][2*N+2];
double C[][] = new double [N+1][N+1];
double eps = 10e-20;
for(k=1;k<=N;k++)
for(j=1;j<=N;j++)
B[k][j]=TB[k][j];
for (k=1;k<=N;k++)
{
for (j=1;j<=N+1;j++)
A[k][j]=B[k][j];
for (j=N+2;j<=2*N+1;j++)
A[k][j]=(float)0;
A[k][k-1+N+2]=(float)1;
}
for (k=1;k<=N;k++)
{
maxpivot=Math.abs((double)A[k][k]);
npivot=k;
for (i=k;i<=N;i++)
if (maxpivot<Math.abs((double)A[i][k]))
{
maxpivot=Math.abs((double)A[i][k]);
npivot=i;
}
if (maxpivot>=eps)
{ if (npivot!=k)
for (j=k;j<=2*N+1;j++)
{
temp=A[npivot][j];
A[npivot][j]=A[k][j];
A[k][j]=temp;
} ;
D=A[k][k];
for (j=2*N+1;j>=k;j--)
A[k][j]=A[k][j]/D;
for (i=1;i<=N;i++)
{
if (i!=k)
{
mult=A[i][k];
for (j=2*N+1;j>=k;j--)
A[i][j]=A[i][j]-mult*A[k][j] ;
}
}
}
else
{ // printf("\n The matrix may be singular !!") ;
return(-1);
};
}
/** Copia il risultato nella matrice InvB ***/
for (k=1,p=1;k<=N;k++,p++)
for (j=N+2,q=1;j<=2*N+1;j++,q++)
InvB[p][q]=A[k][j];
return(0);
} /* End of INVERSE */
private void AperB(double _A[][], double _B[][], double _res[][],
int _righA, int _colA, int _righB, int _colB) {
int p,q,l;
for (p=1;p<=_righA;p++)
for (q=1;q<=_colB;q++)
{ _res[p][q]=0.0;
for (l=1;l<=_colA;l++)
_res[p][q]=_res[p][q]+_A[p][l]*_B[l][q];
}
} private void A_TperB(double _A[][], double _B[][], double _res[][],
int _righA, int _colA, int _righB, int _colB) {
int p,q,l;
for (p=1;p<=_colA;p++)
for (q=1;q<=_colB;q++)
{ _res[p][q]=0.0;
for (l=1;l<=_righA;l++)
_res[p][q]=_res[p][q]+_A[l][p]*_B[l][q];
}
}
int _righA, int _colA, int _righB, int _colB) {
int p,q,l;
for (p=1;p<=_colA;p++)
for (q=1;q<=_colB;q++)
{ _res[p][q]=0.0;
for (l=1;l<=_righA;l++)
_res[p][q]=_res[p][q]+_A[p][l]*_B[q][l];
}
}
public void pv(double v[], java.lang.String str) {
System.out.println("------------" + str + "--------------");
System.out.println(" " + v[1] + " " + v[2] + " " + v[3]
+ " " + v[4] + " " + v[5] + " " + v[6] );
System.out.println("------------------------------------------");
}
public void pm(double S[][], java.lang.String str) {
System.out.println("------------" + str + "--------------");
System.out.println(" " + S[1][1] + " " + S[1][2] + " " + S[1][3]
+ " " + S[1][4] + " " + S[1][5] + " " + S[1][6] ); System.out.println(" " + S[2][1] + " " + S[2][2] + " " + S[2][3]
+ " " + S[2][4] + " " + S[2][5] + " " + S[2][6] ); System.out.println(" " + S[3][1] + " " + S[3][2] + " " + S[3][3]
+ " " + S[3][4] + " " + S[3][5] + " " + S[3][6] ); System.out.println(" " + S[4][1] + " " + S[4][2] + " " + S[4][3]
+ " " + S[4][4] + " " + S[4][5] + " " + S[4][6] ); System.out.println(" " + S[5][1] + " " + S[5][2] + " " + S[5][3]
+ " " + S[5][4] + " " + S[5][5] + " " + S[5][6] ); System.out.println(" " + S[6][1] + " " + S[6][2] + " " + S[6][3]
+ " " + S[6][4] + " " + S[6][5] + " " + S[6][6] );
System.out.println("------------------------------------------");
}
public void draw_conic(double pvec[], int nptsk, double points[][]) {
int npts=nptsk/2;
double u[][] = new double[3][npts+1];
double Aiu[][] = new double[3][npts+1];
double L[][] = new double[3][npts+1];
double B[][] = new double[3][npts+1];
double Xpos[][] = new double[3][npts+1];
double Xneg[][] = new double[3][npts+1];
double ss1[][] = new double[3][npts+1];
double ss2[][] = new double[3][npts+1];
double lambda[] = new double[npts+1];
double uAiu[][] = new double[3][npts+1];
double A[][] = new double[3][3];
double Ai[][] = new double[3][3];
double Aib[][] = new double[3][2];
double b[][] = new double[3][2];
double r1[][] = new double[2][2];
double Ao, Ax, Ay, Axx, Ayy, Axy;
double pi = 3.14781;
double theta;
int i;
int j;
double kk;
Ao = pvec[6];
Ax = pvec[4];
Ay = pvec[5];
Axx = pvec[1];
Ayy = pvec[3];
Axy = pvec[2]; A[1][1] = Axx; A[1][2] = Axy/2;
A[2][1] = Axy/2; A[2][2] = Ayy;
b[1][1] = Ax; b[2][1] = Ay; // Generate normals linspace
for (i=1, theta=0.0; i<=npts; i++, theta+=(pi/npts)) {
u[1][i] = Math.cos(theta);
u[2][i] = Math.sin(theta); }
inverse(A,Ai,2);
AperB(Ai,b,Aib,2,2,2,1);
A_TperB(b,Aib,r1,2,1,2,1);
r1[1][1] = r1[1][1] - 4*Ao; AperB(Ai,u,Aiu,2,2,2,npts);
for (i=1; i<=2; i++)
for (j=1; j<=npts; j++)
uAiu[i][j] = u[i][j] * Aiu[i][j]; for (j=1; j<=npts; j++) {
if ( (kk=(r1[1][1] / (uAiu[1][j]+uAiu[2][j]))) >= 0.0)
lambda[j] = Math.sqrt(kk);
else
lambda[j] = -1.0; } // Builds up B and L
for (j=1; j<=npts; j++)
L[1][j] = L[2][j] = lambda[j];
for (j=1; j<=npts; j++) {
B[1][j] = b[1][1];
B[2][j] = b[2][1]; }
for (j=1; j<=npts; j++) {
ss1[1][j] = 0.5 * ( L[1][j] * u[1][j] - B[1][j]);
ss1[2][j] = 0.5 * ( L[2][j] * u[2][j] - B[2][j]);
ss2[1][j] = 0.5 * ( -L[1][j] * u[1][j] - B[1][j]);
ss2[2][j] = 0.5 * ( -L[2][j] * u[2][j] - B[2][j]); } AperB(Ai,ss1,Xpos,2,2,2,npts);
AperB(Ai,ss2,Xneg,2,2,2,npts); for (j=1; j<=npts; j++) {
if (lambda[j]==-1.0) {
points[1][j] = -1.0;
points[2][j] = -1.0;
points[1][j+npts] = -1.0;
points[2][j+npts] = -1.0;
}
else {
points[1][j] = Xpos[1][j];
points[2][j] = Xpos[2][j];
points[1][j+npts] = Xneg[1][j];
points[2][j+npts] = Xneg[2][j];
}
}
}
public void paint(Graphics g) {
int np = points.size(); // number of points
double D[][] = new double[np+1][7];
double S[][] = new double[7][7];
double Const[][] = new double[7][7];
double temp[][] = new double [7][7];
double L[][] = new double [7][7];
double C[][] = new double [7][7]; double invL[][] = new double [7][7];
double d[] = new double [7];
double V[][] = new double [7][7];
double sol[][] = new double [7][7];
double tx,ty;
int nrot=0;
int npts=50; double XY[][] = new double[3][npts+1];
double pvec[] = new double[7];
g.setColor(getForeground());
g.setPaintMode(); // draw a border around the canvas
g.drawRect(0,0, size().width-1, size().height-1); // draw the control points
for (int i=0; i < np; i++) {
ControlPoint p = (ControlPoint)points.elementAt(i);
g.drawOval(p.x-p.PT_SIZE, p.y-p.PT_SIZE, p.PT_SIZE*2, p.PT_SIZE*2);
//g.drawString(String.valueOf(i),p.x+p.PT_SIZE,p.y-p.PT_SIZE);
}
switch (mode) {
case(FPF):
//System.out.println("FPF mode");
Const[1][3]=-2;
Const[2][2]=1;
Const[3][1]=-2;
break;
case(TAUBIN):
g.drawString(warn_taub_str,size().width/18 , size().height/18 );
break;
case(BOOKSTEIN):
//System.out.println("BOOK mode");
Const[1][1]=2;
Const[2][2]=1;
Const[3][3]=2; } if (np<6)
return; // Now first fill design matrix
for (int i=1; i <= np; i++)
{
tx = ((ControlPoint)points.elementAt(i-1)).x;
ty = ((ControlPoint)points.elementAt(i-1)).y;
D[i][1] = tx*tx;
D[i][2] = tx*ty;
D[i][3] = ty*ty;
D[i][4] = tx;
D[i][5] = ty;
D[i][6] = 1.0;
}
//pm(Const,"Constraint");
// Now compute scatter matrix S
A_TperB(D,D,S,np,6,np,6);
//pm(S,"Scatter");
//pm(L,"Cholesky");
inverse(L,invL,6);
//pm(invL,"inverse");
AperB_T(Const,invL,temp,6,6,6,6);
AperB(invL,temp,C,6,6,6,6);
//pm(C,"The C matrix");
jacobi(C,6,d,V,nrot);
//pm(V,"The Eigenvectors"); /* OK */
//pv(d,"The eigevalues");
A_TperB(invL,V,sol,6,6,6,6);
//pm(sol,"The GEV solution unnormalized"); /* SOl */ // Now normalize them
for (int j=1;j<=6;j++) /* Scan columns */
{
double mod = 0.0;
for (int i=1;i<=6;i++)
mod += sol[i][j]*sol[i][j];
for (int i=1;i<=6;i++)
sol[i][j] /= Math.sqrt(mod);
} //pm(sol,"The GEV solution"); /* SOl */
double zero=10e-20;
double minev=10e+20;
int solind=0;
switch (mode) {
case(BOOKSTEIN): // smallest eigenvalue
for (i=1; i<=6; i++)
if (d[i]<minev && Math.abs(d[i])>zero)
solind = i;
break;
case(FPF):
for (i=1; i<=6; i++)
if (d[i]<0 && Math.abs(d[i])>zero)
solind = i;
}
// Now fetch the right solution
for (int j=1;j<=6;j++)
pvec[j] = sol[j][solind];
//pv(pvec,"the solution"); // ...and plot it
draw_conic(pvec,npts,XY);
for (int i=1; i<npts; i++) {
if (XY[1][i]==-1 || XY[1][i+1]==-1 )
continue;
else
if (i<npts)
g.drawLine((int)XY[1][i],(int)XY[2][i],(int)XY[1][i+1],(int)XY[2][i+1] );
else
g.drawLine((int)XY[1][i],(int)XY[2][i],(int)XY[1][1],(int)XY[2][1] );
}
}
}class CurveControls extends Panel {
CurvePanel target;
Checkbox cb_add;
Checkbox cb_move;
Checkbox cb_delete;
String st_add_label = "Add Points";
String st_move_label = "Move Points";
String st_delete_label = "Delete Points"; public CurveControls(CurvePanel target) {
this.target = target;
setLayout(new FlowLayout(FlowLayout.CENTER));
setBackground(Color.lightGray);
Button clear = new Button("Clear");
add("West",clear); CheckboxGroup action_group = new CheckboxGroup();
add(cb_add = new Checkbox(st_add_label, action_group, true));
add(cb_move = new Checkbox(st_move_label, action_group, false));
add(cb_delete = new Checkbox(st_delete_label, action_group, false));
} public void paint(Graphics g) {
Rectangle r = bounds(); g.setColor(Color.lightGray);
g.draw3DRect(0, 0, r.width, r.height, false);
} public boolean action(Event e, Object arg) {
if (e.target instanceof Checkbox) {
String cbox = ((Checkbox)(e.target)).getLabel();
if (cbox.equals(st_add_label)) {
target.setAction(CurvePanel.ADD);
} else if (cbox.equals(st_move_label)) {
target.setAction(CurvePanel.MOVE);
} else if (cbox.equals(st_delete_label)) {
target.setAction(CurvePanel.DELETE);
}
} else if (e.target instanceof Button) {
String button = ((Button)(e.target)).getLabel();
if (button.equals("Clear")) {
target.clearPoints(); // After clearing the control points, put the user back into
// ADD mode, since none of the other modes make any sense.
cb_add.setState(true);
cb_delete.setState(false);
cb_move.setState(false);
target.setAction(CurvePanel.ADD);
target.repaint();
}
}
return true;
}
}class CurveControls2 extends Panel {
CurvePanel target;
Checkbox cb_hermite;
Checkbox cb_bezier;
Checkbox cb_bspline;
String st_book_label = "Bookstein";
String st_taubin_label = "Taubin";
String st_fpf_label = "Ellipse-specific";
Scrollbar scroll;
Label precision_display; public CurveControls2(CurvePanel target) {
this.target = target;
setLayout(new FlowLayout(1)); CheckboxGroup type_group = new CheckboxGroup();
add(cb_hermite = new Checkbox(st_book_label, type_group, true));
add(cb_bezier = new Checkbox(st_taubin_label, type_group, false));
// add(cb_bezier = new Checkbox("foo", type_group, false));
add(cb_bspline = new Checkbox(st_fpf_label, type_group, false)); // Set up the scrollbar: Value 15, Page 5, Min 2, Max 40
//add(scroll = new Scrollbar(Scrollbar.HORIZONTAL, 15, 5, 2, 40));
//target.setPrecision(scroll.getValue());
//add(precision_display = new Label("Precision: "+
// String.valueOf(scroll.getValue()),Label.LEFT));
} public void paint(Graphics g) {
Rectangle r = bounds(); g.setColor(Color.lightGray);
g.draw3DRect(0, 0, r.width, r.height, false);
} public boolean handleEvent(Event e) {
switch (e.id) {
case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_LINE_UP:
case Event.SCROLL_PAGE_DOWN:
case Event.SCROLL_PAGE_UP:
target.repaint();
return true;
case Event.ACTION_EVENT:
// Handle other action events
if (e.target instanceof Checkbox) {
String cbox = ((Checkbox)(e.target)).getLabel();
if (cbox.equals(st_book_label)) {
target.setCurveType(CurvePanel.BOOKSTEIN);
} else if (cbox.equals(st_taubin_label)) {
// system.out.println("------------------------------------------");
// g.drawString("Taubin not implemented",e.x+5,e.y-5);
// System.out.println("Taubin algorithm not yet implemented!");
target.setCurveType(CurvePanel.TAUBIN);
} else if (cbox.equals(st_fpf_label)) {
target.setCurveType(CurvePanel.FPF);
}
}
target.repaint();
return(true);
default:
return(false);
}
}
}