import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.applet.*; import java.awt.geom.*; import java.math.*; public class ScaleCanvas extends Canvas implements MouseListener, MouseMotionListener { Complex SOURCE=new Complex(0,0); AffineTransform[] A=new AffineTransform[2]; public ScaleCanvas() { } public void setScales(int m,int n) { A[0]=AffineTransform.getTranslateInstance(m,m); A[1]=AffineTransform.getScaleInstance(n,-n); } public void setScales(int m1,int m2,int n) { A[0]=AffineTransform.getTranslateInstance(m1,m2); A[1]=AffineTransform.getScaleInstance(n,-n); } public void paint(Graphics g2) {} public GeneralPath transform(GeneralPath H) { GeneralPath HH=new GeneralPath(H); HH.transform(A[1]); //scale HH.transform(A[0]); //translate return(HH); } /*This scales so that a particular general path fits exactly in the box*/ public static AffineTransform[] preFit(GeneralPath gp,double x,double y,double w,double h) { AffineTransform[] AFF=new AffineTransform[2]; Rectangle2D R0=gp.getBounds2D(); Rectangle2D.Float R1=(Rectangle2D.Float)(R0); double[] t={R1.x,R1.y,R1.x+R1.getWidth(),R1.y+R1.getHeight()}; double x1=1.0*(w)/(t[2]-t[0]); double x2=1.0*(h)/(t[3]-t[1]); double sc=x1; if(sc>x2) sc=x2; AFF[1]=AffineTransform.getScaleInstance(sc,sc); double cenx=(t[0]+t[2])/2.0; double ceny=(t[1]+t[3])/2.0; double targetx=x+1.0*w/2; double targety=y+1.0*h/2; double xx=targetx-cenx*sc; double yy=targety-ceny*sc; AFF[0]=AffineTransform.getTranslateInstance(xx,yy); return(AFF); } /**ZOOM: This routine is the companion to the scaling routine. After I have zoomed into the picture in some way, my further mouse clicks have different meanings than they did before the zoom. In other words, suppose that I dilate the picture by 100000. When I click on the point with pixel value (50,50) I really mean to select the number (.00005,.00005). This routine changes the pixel value of the point to the intended value.*/ public Complex unTransform(Point X) { double ux=A[0].getTranslateX(); double uy=A[0].getTranslateY(); double tx=X.x; double ty=X.y; double sx=A[1].getScaleX(); double sy=A[1].getScaleY(); ux=(ux-tx)+tx; uy=(uy-ty)+ty; tx=tx-ux; ty=ty-uy; tx=tx/sx; ty=ty/sy; return(new Complex(tx,ty)); } /**ZOOM: this routine scales up or down with the mouse click. The first argument is the point about which you scale, and the second argument just tells you whether to go up or down. The basic idea is that I have globally defined some AffineTransform objects. These will rescale a GeneralPath whenever I draw it. So, I just modify the components of these AffineTransforms whenever I do this routine.*/ public void scaleUp(Point X,int k) { double scale=Math.pow(2,0.25); double ss=scale; if(k==1) ss=1/scale; double sx=A[1].getScaleX(); double sy=A[1].getScaleY(); double tx=X.x; double ty=X.y; double ux0=A[0].getTranslateX(); double uy=A[0].getTranslateY(); double ux1=ss*(ux0-tx)+tx; uy=ss*(uy-ty)+ty; sx=sx*ss; sy=sy*ss; A[1]=AffineTransform.getScaleInstance(sx,sy); A[0]=AffineTransform.getTranslateInstance(ux1,uy); } public void drawSource(Graphics2D g) { drawPoint(g,SOURCE,.001,Color.white,16,true); } public void drawPoint(Graphics2D g,Complex z,double r,Color C,int q,boolean FILL) { GeneralPath gp=new GeneralPath(); float x=(float)(z.x); float y=(float)(z.y); for(int i=0;i<=q;++i) { double c=Math.cos(2*Math.PI*i/q); double s=Math.sin(2*Math.PI*i/q); c=r*c+z.x; s=r*s+z.y; if(i==0) gp.moveTo((float)(c),(float)(s)); if(i!=0) gp.lineTo((float)(c),(float)(s)); } gp=transform(gp); g.setColor(C); if(FILL==true) g.fill(gp); g.draw(gp); } public void mousePressed(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseMoved(MouseEvent e) {} public void mouseClicked(MouseEvent e) {} public void mouseDragged(MouseEvent e) {} public void doScale(MouseEvent e) { MouseData J=MouseData.process(e); int mode=J.mode; if(mode==1) scaleUp(J.X,-1); if(mode==3) scaleUp(J.X,+1); if(mode==2) { Complex temp=unTransform(J.X); SOURCE=temp; } } public void doScale2(MouseEvent e) { MouseData J=MouseData.process(e); int mode=J.mode; if(mode==2) { Complex temp=unTransform(J.X); SOURCE=temp; } } }