001    /*
002     * BallRenderer.java
003     *
004     * Created on February 7, 2003, 4:44 PM
005     */
006    
007    package ballworld;
008    
009    import cs101.lang.Animate;
010    import cs101.lang.AnimatorThread;
011    
012    import java.awt.Point;
013    import java.awt.Color;
014    import java.awt.Graphics2D;
015    import java.awt.geom.Ellipse2D;
016    import java.awt.geom.Ellipse2D.Double;
017    
018    
019    /** Holds and animates one ball which can be rendered upon requested. Also
020     * provides methods for transforming between world corrdinates (cartesian
021     * with 0,0 at center) and GUI coordinates (0,0 at upper left with inverted
022     * vertical scale as is the norm in Java GUI components)
023     *
024     * @author Patrick G. Heck, gus.heck@olin.edu
025     */
026    public class BallRenderer {
027        
028        private Ball myBall;
029        private BallWorld myWorld;
030        private AnimatorThread at;
031        private boolean selected;
032        
033        /** Creates a new instance of BallRenderer
034         * @param b The {@link Ball} we are responsible for rendering
035         * @param w The {@link BallWorld} that
036         */
037        public BallRenderer(Ball b, BallWorld w) {
038            this.myBall = b;
039            this.myWorld = w;
040            if (b instanceof Animate) {
041                at = new AnimatorThread((Animate)b,AnimatorThread.START_IMMEDIATELY,0,50);
042            }        
043        }
044    
045        /**
046         * Draw the ball on the given graphics context.
047         *
048         * @param G  A graphics context for drawing
049         */
050        public void drawBall(Graphics2D G) {
051            double radius = myBall.getRadius();
052            double diam = radius*2;
053            Point worldPoint = new Point();
054            worldPoint.setLocation(myBall.getX(), myBall.getY());
055            Point guiPoint = BallRenderer.transformWorld2GUI(worldPoint, myWorld);
056            double x = guiPoint.getX();
057            double y = guiPoint.getY();
058            Ellipse2D.Double ball = 
059                new Ellipse2D.Double(x-radius,y-radius,diam,diam);
060            if(selected) {
061                G.setPaint(Color.red);
062            } else {
063                G.setPaint(Color.black);
064            }
065            G.fill(ball);
066        }
067        
068        /**
069         * Get the ball held by this renderer.
070         *
071         * @return the ball contained by this renderer.
072         */
073        public Ball getBall() {
074            return myBall;
075        }
076        
077        /**
078         * Set the selection status for this ball;
079         * 
080         * @param state the state to set (selected or not)
081         */
082        public void setSelected(boolean state) {
083            selected = state;
084        }
085        
086        /** Check whether or not the given point resides within the radius of the
087         * ball.
088         *
089         * @param p The point to check
090         * @return <code>true</code> if our ball contains this point, <code>false</code> otherwise.
091         */
092        public boolean containsPoint(Point p) {
093            if (distanceTo(p) <= myBall.getRadius()) {
094                return true;
095            }
096            return false;
097        }
098        
099         /** Find the distance from our ball to the given point.
100          *
101          * @param p The point to measure the distance to
102          * @return The distance between the given coordinate and our ball
103          */
104        public double distanceTo(Point p) {
105            double x0 = myBall.getX();
106            double y0 = myBall.getY();
107            double x1 = p.getX();
108            double y1 = p.getY();
109            
110            return Math.pow(Math.pow(x0-x1,2) + Math.pow(y0-y1,2),0.5);
111            
112        }
113        
114        /**
115         * Stop the Animator thread. 
116         */
117        public void stop() {
118            at.stopExecution();
119        }
120        
121        /** Convert a point from world coordinates to GUI coordinates.
122         * World coordinates are 0,0 at the center of the window with Y
123         * increasing in the up direction (standard Cartesian coordinates).
124         * GUI Coordinates are 0,0 at the upper left with Y increasing downwards
125         *
126         * @return A point in GUI coordinates
127         * @param w The world we are converting from
128         * @param p A point in world coordinates
129         */
130        public static Point transformWorld2GUI(Point p, BallWorld w) {
131            Point newP = new Point();
132            double worldH = w.getGUIMaxY();
133            double worldW = w.getGUIMaxX();
134            newP.setLocation(p.getX() + worldW/2,
135                            worldH/2 - p.getY());
136            
137            return newP;
138        }
139        
140        /** Convert a point from GUI coordinates to world coordinates.
141         * World coordinates 0,0 at the center of the window with Y
142         * increasing in the up direction (standard Cartesian coordinates).
143         * GUI Coordinates are 0,0 at the upper left with Y increasing downwards
144         *
145         * @return A point in world coordinates
146         * @param w The world we are converting to
147         * @param p A point in GUI coordinates
148         */
149        public static Point transformGUI2World(Point p, BallWorld w) {
150            Point newP = new Point();
151            double worldH = w.getGUIMaxY();
152            double worldW = w.getGUIMaxX();
153            newP.setLocation(p.getX() - worldW/2,
154                            worldH/2 - p.getY());
155            
156            return newP;
157        }
158    }