package ProGAL.geom2d.viewer; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; import ProGAL.geom2d.*; /** * A graphics class for viewing 2D scenes. * Many of the Shape-subclasses specified in the ProGAL.geom2d * package can be added to a J2DScene object and are automatically * painted. For instance the following code creates a scene with 3 circles, two lines * indicating unit axis, and a text label. *
 * J2DScene scene = new J2DScene();
 * scene.addShape(new LineSegment(new Point(0,0), new Point(1,0)), Color.BLACK);
 * scene.addShape(new LineSegment(new Point(0,0), new Point(0,1)), Color.BLACK);
 * scene.addShape(new Circle(new Point(0,0), 1), new Color(250,0,0,100), 0.05, false);
 * scene.addShape(new Circle(new Point(1,0), 0.2), Color.GREEN);
 * scene.addShape(new Circle(new Point(0,1), 0.2), Color.BLUE);
 * scene.addShape(new TextShape("(1,0)", new Point(1,0), 0.2), Color.BLACK);
 * 
 * JPanel canvas = scene.getCanvas();
 * 
 * JFrame frame = new JFrame();
 * frame.setSize(400,400);
 * frame.getContentPane().add( canvas );
 * frame.setVisible(true);
 * 
* * The repaint() method must be called every time the position of * shapes has changed and the canvas should be updated. The pointers * to added shapes are stored, so subsequent changes will be visible on the canvas when * repaint() is called. The following example shows how to animate a circle * rotating around origo. *
 * J2DScene scene = J2DScene.createJ2DSceneInFrame();
 * scene.addShape(new LineSegment(new Point(0,0), new Point(1,0)), Color.BLACK);
 * scene.addShape(new LineSegment(new Point(0,0), new Point(0,1)), Color.BLACK);
 * Circle c = new Circle(new Point(0,1), 0.2);
 * scene.addShape(c, Color.BLUE);
 * 
 * double t = 0;
 * while(true){
 * 	c.center().setCoord(0, Math.cos(t));
 * 	c.center().setCoord(1, Math.sin(t));
 * 	scene.repaint();
 * 	t+=0.01;
 * 	try {Thread.sleep(50);} catch (InterruptedException e) {}
 * }
 * 
* As shown in this example, a static method is supplied for conveniently creating a frame * containing a scene-viewer. * * Shapes are painted in the order they are inserted. The addShape method has * support for border width and filling out a shape. * * @author R. Fonseca */ public class J2DScene { public JFrame frame; private final PaintPanel canvasPanel; private final List clickListeners = new LinkedList(); private final List shapes = new ArrayList(); private Point camCenter; double scale; /** * Construct a representation of a 2D scene. */ public J2DScene(){ canvasPanel = new PaintPanel(); camCenter = new Point(0,0); scale = 100; canvasPanel.addKeyListener(new KeyListener() { public void keyTyped(KeyEvent e) {} public void keyReleased(KeyEvent e) {} public void keyPressed(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_C) centerCamera(); if(e.getKeyCode()==KeyEvent.VK_Z) autoZoom(); if(e.getKeyCode()==KeyEvent.VK_S) savePng("J2DSnapshot.png"); } }); canvasPanel.addMouseListener(canvasPanel); canvasPanel.addMouseMotionListener(canvasPanel); canvasPanel.addMouseWheelListener(canvasPanel); canvasPanel.setFocusable(true); } /** Return the panel that this scene is painted on. */ public JPanel getCanvas(){ return canvasPanel; } /** Center the view on the objects in the scene */ public void centerCamera(){ double minX=Double.POSITIVE_INFINITY; double maxX=Double.NEGATIVE_INFINITY; double minY=Double.POSITIVE_INFINITY; double maxY=Double.NEGATIVE_INFINITY; for(ShapeOptions so: shapes){ Point p = so.shape.getCenter(); if(p.x()maxX) maxX = p.x(); if(p.y()>maxY) maxY = p.y(); } camCenter = new Point((minX+maxX)/2, (minY+maxY)/2); repaint(); } /** Zoom the view to enclose all the objects in the scene. */ public void autoZoom(){ double minX=Double.POSITIVE_INFINITY; double maxX=Double.NEGATIVE_INFINITY; double minY=Double.POSITIVE_INFINITY; double maxY=Double.NEGATIVE_INFINITY; for(ShapeOptions so: shapes){ Point p = so.shape.getCenter(); if(p.x()maxX) maxX = p.x(); if(p.y()>maxY) maxY = p.y(); } int w = canvasPanel.getWidth(); int h = canvasPanel.getHeight(); if(w==0) w = 1000; if(h==0) h = 700; scale = Math.min(w/(maxX-minX), h/(maxY-minY))*0.9; repaint(); } /** Add a shape to this scene. Currently, *
  • ProGAL.geom2d.Circle
  • *
  • ProGAL.geom2d.LineSegment and
  • *
  • ProGAL.geom2d.viewer.TextShape
  • *
  • ProGAL.geom2d.LSC
* are supported. */ public void addShape(Shape s){ addShape(s,Color.GRAY,0.01,false); } /** Add a shape to this scene with the specified color. Currently, *
  • ProGAL.geom2d.Circle
  • *
  • ProGAL.geom2d.LineSegment and
  • *
  • ProGAL.geom2d.viewer.TextShape
  • *
  • ProGAL.geom2d.LSC
* are supported. */ public void addShape(Shape s, Color c){ addShape(s,c,0.01,false); } public void addShape(Shape s, Color c, double border){ addShape(s,c,border,false); } public void addShape(Shape s, Color c, double border, boolean fill){ shapes.add(new ShapeOptions(s,c,border,fill)); // repaint(); } public void savePng(String fName) { BufferedImage bImg = new BufferedImage(canvasPanel.getWidth(), canvasPanel.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D cg = bImg.createGraphics(); canvasPanel.paintAll(cg); try { if (ImageIO.write(bImg, "png", new File(fName))) { System.out.println("Successfully wrote "+fName); } } catch (IOException e) { e.printStackTrace(); } } /** Remove the specified shape from the scene */ public void removeShape(Shape s) { ShapeOptions opt = null; for(ShapeOptions so: shapes) if(so.shape==s){ opt = so; break; } shapes.remove(opt); // repaint(); } /** Remove all shapes from the scene */ public void removeAllShapes() { // while (!shapes.isEmpty()) shapes.remove(0); shapes.clear(); // repaint(); } /** Add a click-listener that gets called every time an object or the background is clicked */ public void addClickListener(ClickListener cl){ clickListeners.add(cl); } /** Repaint the scene */ public void repaint(){ // canvasPanel.paintImmediately(0, 0, canvasPanel.getWidth(), canvasPanel.getHeight()); canvasPanel.repaint(); } private final static ShapePainter[] shapePainters = { new CirclePainter(), new LineSegmentPainter(), new TextPainter(), new LSCPainter(), new TrianglePainter(), new PolygonPainter(), new LinePainter() }; private static ShapePainter getShapePainter(Shape s){ if(s instanceof Circle) return shapePainters[0]; if(s instanceof LineSegment) return shapePainters[1]; if(s instanceof TextShape) return shapePainters[2]; if(s instanceof LSC) return shapePainters[3]; if(s instanceof Triangle) return shapePainters[4]; if(s instanceof Polygon) return shapePainters[5]; if(s instanceof Line) return shapePainters[6]; return null; } private class PaintPanel extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener{ private static final long serialVersionUID = 1L; public void paint(Graphics g){ Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); for(ShapeOptions so: new LinkedList(shapes)){ if(so==null) continue; Stroke oldStroke = g2d.getStroke(); g2d.setStroke( new BasicStroke( (float)(scale*so.borderWidth), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND) ); // g2d.setColor(so.color); g2d.setPaint(so.color); ShapePainter sp = getShapePainter(so.shape); if(sp==null) System.err.println("J2DScene: ShapePainter not implemented for "+so.shape.getClass().getSimpleName()); else sp.paintShape(so, g2d); g2d.setStroke(oldStroke); } } java.awt.Point lastPoint = null; public void mouseDragged(MouseEvent e) { java.awt.Point p = e.getLocationOnScreen(); // java.awt.Point dP = new java.awt.Point(p.x-lastPoint.x, p.y-lastPoint.y); Point p0 = transformPoint(lastPoint); Point p1 = transformPoint(p); camCenter.addThis(new Vector(p0.x()-p1.x(), p0.y()-p1.y())); repaint(); lastPoint = p; } Point transformPoint(java.awt.Point p){ int w = getWidth(); int h = getHeight(); double pX = (p.x-w/2)/scale + camCenter.x(); double pY = -(p.y-h/2)/scale + camCenter.y(); return new Point(pX,pY); } public void mouseMoved(MouseEvent e) { } public void mouseClicked(MouseEvent e) { Point p = null; Shape shapeClicked = null; for(ShapeOptions so: new LinkedList(shapes)){ if(so.fill){ if(p==null) p = transformPoint(e.getPoint()); if(so.shape.contains(p)) shapeClicked = so.shape; } } for(ClickListener cl: clickListeners){ cl.shapeClicked(shapeClicked, e); } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { lastPoint = e.getLocationOnScreen(); } public void mouseReleased(MouseEvent e) { } public void mouseWheelMoved(MouseWheelEvent e) { double factor =Math.pow(0.97, e.getWheelRotation()); scale*=factor; repaint(); } } public java.awt.Point transformPoint(Point p){ int w = canvasPanel.getWidth(); int h = canvasPanel.getHeight(); int gX = (int)(scale*(p.x()-camCenter.x())+w/2); int gY = (int)(-scale*(p.y()-camCenter.y())+h/2); return new java.awt.Point(gX,gY); } public Point transformPoint(java.awt.Point p){ int w = canvasPanel.getWidth(); int h = canvasPanel.getHeight(); int gX = p.x; int gY = p.y; double x = ((gX-w/2)/scale)+camCenter.x(); double y = ((gY-h/2)/-scale)+camCenter.y(); return new Point(x,y); } class ShapeOptions{ Shape shape; Color color; double borderWidth; boolean fill; ShapeOptions(Shape s, Color c, double bw, boolean f){ this.shape = s; this.color = c; this.borderWidth = bw; this.fill = f; } java.awt.Point transformPoint(Point p){ return J2DScene.this.transformPoint(p); } Point transformPoint(java.awt.Point p){ return J2DScene.this.transformPoint(p); } double getScale(){ return scale; } } /** * Create a frame containing a canvas, display it and return the J2DScene object shown in the frame. * The frame can be retrieved using the J2DScene.frame field. */ public static J2DScene createJ2DSceneInFrame(){ J2DScene scene = new J2DScene(); JFrame frame = new JFrame("J2DScene"); frame.getContentPane().add(scene.canvasPanel); frame.setSize(1000,1000); frame.setVisible(true); scene.frame = frame; return scene; } public static void main(String[] args){ J2DScene scene = J2DScene.createJ2DSceneInFrame(); scene.addShape(new LineSegment(new Point(0,0), new Point(1,0)), Color.BLACK); scene.addShape(new LineSegment(new Point(0,0), new Point(0,1)), Color.BLACK); scene.addShape( new TextShape("(1,0)", new Point(1,0), 0.2) ); scene.addShape( new TextShape("(0,1)", new Point(0,1), 0.2) ); scene.addShape(new Circle(new Point(0.1,0.1), 0.01), Color.BLACK, 0, true); scene.addShape(new Circle(new Point(0.2,0.2), 0.01), Color.BLACK, 0, true); scene.addShape(new LSC(new Point(0,-0.5), new Point(1,-0.4), 0.2), Color.RED); scene.addShape(new LSC(new Point(0,-0.9), new Point(1,-0.9), 0.1), Color.RED, 0, true); Point p = new Point(-2,0); scene.addShape(new Triangle(new Point(-1,0), new Point(-1,1), p), Color.GREEN, 0, true); scene.addShape(new Polygon( new Point[]{ new Point(-1,2), new Point(-1,2.4), new Point(-1.4,2.1), new Point(-1.6,2.8), } ), Color.BLUE,0,true); scene.addShape(new Line(new Point(3,0), new Vector(0.01,-0.03))); scene.centerCamera(); while(true){ p.addThis(new Vector(0.01,0)); scene.repaint(); try { Thread.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }