/* * SpaceCanvas.java * * Created on October 29, 2005, 8:53 AM */ package Current.canvases.ParameterSpace; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import java.util.*; import org.pat.graphics.boxed.ListenString; import Current.popups.Settings.SettingsRequest; import Current.popups.ImageSave.ImageSaver; import Current.gui.*; import Current.basic.*; import Current.manage.*; import Current.manage.Tiles.*; import Current.manage.ParameterSpace.*; /** * * @author pat */ public class SpaceCanvas extends DBCanvas implements MouseListener, MouseMotionListener, ImageSaver { Manager M; SpaceTileManager STM; // this is the bounding box for the parameter space. private final GeneralPath space=new GeneralPath(); // This Affine Transform takes the viewing area to the [0,1]x[0,1] unit square. AffineTransform square; // This controls user zooming of the canvas AffineTransform zoom; // The resulting transform used for drawing AffineTransform transform; // The inverse of transform AffineTransform inverse; //////// viewing area Rectangle2D.Double view; ////////// OBJECTS ListenString Doc,Set; //ListenSquare Doc; ///////// Currently Selected Tile Tile selected; ////////// SOME BASIC CONSTANTS public double zoomAmount; private double triX,triY; // represents the currently selected triangle private boolean obtuse=true; // coordinate scheme ////////// Interaction Mode public int mode; // used for painting private Image offscreen; private int width; private int height; // needs to be stored when dragging int mouse_mode; // used when a redraw is needed boolean forceRedraw=false; /** Do you want to center when fit tile is used? */ public boolean center_on_fit=false; /** Do you want to show the help button? */ public boolean show_help=true; /** Creates a new instance of SpaceCanvas */ public SpaceCanvas(Manager M) { this.M=M; this.STM=M.STM; triX=M.getX(); triY=M.getY(); space.moveTo(0,0); space.lineTo(1,0); space.lineTo(1,1); space.lineTo(0,1); space.closePath(); setFont(new Font("sanserif", Font.PLAIN, 12)); // set width and height to dummy values: width=height=0; // set the mode to std mode=0; zoom=new AffineTransform(); square=new AffineTransform(); ////////// OBJECTS Doc=new ListenString("?",this); Doc.setColors(Color.white, Color.black); Doc.setLeft(0); Doc.setTop(0); Set=new ListenString("s",this); Set.setColors(Color.white, Color.black); Set.setLeft(Doc.getRight()); Set.setTop(0); //Doc=new ListenSquare(2,2,12,12,Color.black); //Doc.on=1; ////////// SOME BASIC CONSTANTS zoomAmount=1.2; //// FINAL SETUP addMouseListener(this); addMouseMotionListener(this); //////// select the current tile selected=M.getSelectedTile(); M.addListener(this); M.ISM.add("parameter space",this); } /** Reset the main AffineTransform * This should be called after zooming in or out * and after resizing the canvas */ public void resetTransform(){ transform=new AffineTransform(square); AffineTransform temp=new AffineTransform(); if (!obtuse) { temp.translate(0.5, 0.5); temp.shear(1/Math.sqrt(3),0); temp.scale(1,Math.sqrt(3)/2); temp.translate(-0.5, -0.5); } transform.concatenate(temp); transform.concatenate(zoom); try { inverse=transform.createInverse(); } catch (Exception e) { System.err.println("Non-invertible transform exception. This error should never happen"); System.err.flush(); } Point2D.Double p=new Point2D.Double(),q=new Point2D.Double(); inverse.transform(new Point2D.Double(0,getHeight()-1),p); inverse.transform(new Point2D.Double(getWidth()-1,0),q); view=new Rectangle2D.Double(p.getX(),p.getY(), q.getX()-p.getX(),q.getY()-p.getY()); M.setViewingRectangle(view); } /** Create the AffineTransform, square, * which sends the [0,1]x[0,1] square to the interior of canvas. * It adds a 5% border. */ public void resetSquare(){ // set transform to be the identity affine transform square=new AffineTransform(); // Steps 1 & 2 take the [0,1]x[0,1] square to the window // by some euclidean transform // Steps 3 4 & 5 add a 5% border. // Step 5 translate 0,0 back to the center square.translate(width/2.0,height/2.0); // Step 4: scale by 90% square.scale(.9, .9); // Step 3 translate the center to the point 0,0 square.translate(-width/2.0,-height/2.0); int size; if (widthr.getHeight()) scale=1/r.getWidth(); else scale=1/r.getHeight(); // Step 3: translate the center to (.5,.5) zoom.translate(0.5,0.5); // Step 2: scale to the right size zoom.scale(scale,scale); // Step 1: move the center of the rectangle to (0,0); zoom.translate(-r.getCenterX(),-r.getCenterY()); resetTransform(); spaceChanged(); if (center_on_fit) { M.setParameter(r.getCenterX(),r.getCenterY()); } } public void mouseClicked(MouseEvent e) { if (show_help) { if (Doc.contains(e)) { M.mcbSend(new HelpDocument("parameter_space.html")); //M.setExplain("This window allows you to examine the parameter space of all triangles. \n\n Left click to zoom in and right click to zoom out.\n\n The middle button moves the point in the parameter space. You can hold down the middle mouse button while moving the mouse to smoothly change the point in the parameter space. In particular, the unfolding window will become animated. You can perform other actions by selecting an interaction mode from the green parameter space controller canvas."); return; } if (Set.contains(e)) { M.mcbSend(new SettingsRequest(ParameterSpaceManager.ColorSettings.class)); return; } } int mode=M.mode; if(M.mouse==1) { if(e.getButton()==MouseEvent.BUTTON1) mode=1; if(e.getButton()==MouseEvent.BUTTON2) mode=2; if(e.getButton()==MouseEvent.BUTTON3) mode=3; } Point2D.Double p=new Point2D.Double(); inverse.transform(new Point2D.Double(e.getX(),e.getY()),p); switch (mode){ case 1: zoomIn(p.getX(),p.getY()); break; case 2: if (space.contains(p)){ Tile temp=STM.selectTile(p.getX(),p.getY()); boolean changed=false, changed2=false; if (temp!=null){ switch (this.mode){ case 2: // color temp.setColor(M.getColor()); //STM.notifyListeners(); changed=true; break; case 3: // raise STM.raise(temp); changed2=true; break; case 4: // lower STM.lower(temp); changed2=true; break; case 5: // erase STM.delete(temp); changed2=true; break; case 6: // fit fit(temp.getBounds()); changed2=true; break; } if (temp!=selected) { M.selectTile(temp); M.spaceChanged(); } else if (changed) { M.selectedTileModified(); M.spaceChanged(); } else if (changed2) { M.spaceChanged(); } } M.setParameter(p.getX(),p.getY()); } break; case 3: zoomOut(p.getX(),p.getY()); break; } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { mouse_mode=M.mode; if(M.mouse==1) { if(e.getButton()==MouseEvent.BUTTON1) mouse_mode=1; if(e.getButton()==MouseEvent.BUTTON2) mouse_mode=2; if(e.getButton()==MouseEvent.BUTTON3) mouse_mode=3; } } public void mouseReleased(MouseEvent e) { } public void mouseDragged(MouseEvent e) { Point2D.Double p=new Point2D.Double(); inverse.transform(new Point2D.Double(e.getX(),e.getY()),p); if ((mouse_mode==2) && (space.contains(p))) { M.setParameter(p.getX(),p.getY()); } } public void mouseMoved(MouseEvent e) { } public void mcbReceive(Parameter p) { Complex Z=p.getZ(); //System.out.println("received "+p); if ((triX!=Z.x)||(triY!=Z.y)){ triX=Z.x; triY=Z.y; repaint(); } } public void changed() { if (offscreen!=null) offscreen.flush(); if ((width!=getWidth())||(height!=getHeight())){ width=getSize().width; height=getSize().height; resetSquare(); } if (obtuse != M.global.affine_coordinate_scheme.get().equals("obtuse")) { obtuse=M.global.affine_coordinate_scheme.get().equals("obtuse"); resetTransform(); } offscreen = createImage(getSize().width, getSize().height); Graphics g2 = offscreen.getGraphics(); Graphics2D g=(Graphics2D) g2; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); M.render(g,transform); g.dispose(); g2.dispose(); } public void spaceChanged() { forceRedraw=true; repaint(); } public void mcbReceive(Tile t) { if ( (t.isPaintable()) && (mode==6)) {// fit fit(t.getBounds()); } } public void mcbReceive(TileModified tm) { //System.out.println("Thread \""+Thread.currentThread().getName()+"\" rendering SpaceCanvas"); forceRedraw=true; repaint(); } public void mcbReceive(SpaceChange sc) { spaceChanged(); } public void mcbCleanup() { M.remove(this); } public void mcbReceive(Manager.GlobalSettings gs) { repaint(); } }