1   package main;
2   
3   import interfaces.*;
4   import simworldobjects.*;
5   
6   import javax.swing.*;
7   import java.awt.image.*;
8   import java.awt.*;
9   import java.lang.*;
10  import java.util.*;
11  import java.awt.geom.*;
12  
13  /** Provides a simple display for any SimWorld. In general is responsible for
14   * drawing and redrawing all the objects used to display the simulation.
15   * @author Graham Ritchie
16   * @Modifyer Simon Zienkiewicz
17   */
18  public class SimpleDisplay extends SimDisplay
19  {
20      private SimWorld world;
21      private Graphics2D g2;
22      private BasicStroke stroke;
23      private Color color;
24      private JTextField lcd = new JTextField();
25      private java.awt.image.VolatileImage volImage;
26      private Color objectColorArray[] = {Color.yellow,Color.yellow,Color.black,Color.blue,Color.gray,Color.green};
27      private String shapeNames[] = {"robot","light","sensorTouch","sensorLight","wall","ground","road"};
28      private SimUI simulator;
29  
30      /** Sets up this display
31       * @param simulator the simulator associated with the SimDisplay
32       * @param s the SimWorld to be displayed
33       */
34  
35      public SimpleDisplay(SimWorld s, SimUI simulator)
36      {
37              // set world
38              world=s;
39              this.repaint();
40              //stroke=new BasicStroke(1.0f,BasicStroke.CAP_SQUARE,BasicStroke.JOIN_BEVEL);
41              this.add(lcd);
42              lcd.setVisible(false);
43              this.simulator = simulator;
44              
45      }
46      
47      /** Main repaint method, paints all the objects in the simulator
48       * @param g java graphics object
49       */
50      public void paintComponent(Graphics g)
51      {
52          //System.out.println("SimpleDisply: repaint");
53          // paint background
54          super.paintComponent(g);
55          //sets the bounds of the image to that of the size of the world
56          this.setBounds(0,0,((BasicSimWorld)world).getWorldDimensions()[0], ((BasicSimWorld)world).getWorldDimensions()[2]);
57          g.setColor(Color.lightGray);
58          g.drawRect(0,0,((BasicSimWorld)world).getWorldDimensions()[0]-1, ((BasicSimWorld)world).getWorldDimensions()[2]-1);
59          
60          //if grid is off then the background will be painted by simdisplay
61          if(!simulator.isGridOn())this.setBackground(world.getWorldColor());
62  
63          // cast g to a Graphics2D instance
64          g2=(Graphics2D)g;
65  
66          // get the world's object list
67          LinkedList list=world.getObjectList();
68  
69          // draw a shape for each object
70  
71          for (int i=0;i<list.size();i++)
72          {
73              // get each object in the list in turn
74              SimObject o=(SimObject)list.get(i);
75              
76              stroke=new BasicStroke(1.0f,BasicStroke.CAP_SQUARE,BasicStroke.JOIN_BEVEL);
77              
78              // create a shape for this object
79              Shape s=getShape(o);
80  
81              // rotate shape to correct bearing
82              s=rotateShape(s,o.getActualBearingXZ(),o.getXCoord(),o.getZCoord());
83  
84              // draw shape on the screen
85              if(o instanceof SimGround){              
86                  g2.setPaint(((SimGround)o).getOutlineColor());
87                  if(((SimGround)o).getSelected()) stroke=new BasicStroke(10.0f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL);
88              }
89              else if(o instanceof SimWall){
90                  g2.setPaint(((SimWall)o).getOutlineColor());
91                  if(((SimWall)o).getSelected()) stroke=new BasicStroke(10.0f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL);
92              }
93              else if(o instanceof SimRCX){
94                  if(((SimRCX)o).getSelected()){
95                      g2.setPaint(Color.yellow);
96                      g2.drawOval((int)(o.getXCoord()-70),(int)(o.getZCoord()-70),140,140);
97                      g2.drawOval((int)(o.getXCoord()-65),(int)(o.getZCoord()-65),130,130);
98                      g2.drawLine((int)(o.getXCoord()-45),(int)(o.getZCoord()-45), (int)(o.getXCoord()+45), (int)(o.getZCoord()+45));
99                      g2.drawLine((int)(o.getXCoord()+45),(int)(o.getZCoord()-45), (int)(o.getXCoord()-45), (int)(o.getZCoord()+45));
100                 }
101                 g2.setPaint(Color.black);
102             }
103             else g2.setPaint(Color.black);
104                 
105             Shape outline=stroke.createStrokedShape(s);
106             g2.draw(outline);
107             g2.setPaint(getColorLibrary(o.getType().toString(),o));
108             g2.fill(s);
109 
110             //in order to mark a selcted ground piece
111             if(o instanceof SimGround || o instanceof SimWall){
112                 if(o instanceof SimGround){
113                   if(((SimGround)o).getSelected()) {
114                       g2.setPaint(((SimGround)o).getOutlineColor());
115                       Line2D.Double line1 = new Line2D.Double((int)(o.getXCoord()-o.getWidth()/2),(int)(o.getZCoord()-o.getLength()/2), (int)(o.getXCoord()+o.getWidth()/2), (int)(o.getZCoord()+o.getLength()/2));
116                       Line2D.Double line2 = new Line2D.Double((int)(o.getXCoord()+o.getWidth()/2), (int)(o.getZCoord()-o.getLength()/2),(int)(o.getXCoord()-o.getWidth()/2), (int)(o.getZCoord()+o.getLength()/2));
117                       g2.draw(rotateShape(line1, o.getActualBearingXZ(),o.getXCoord(),o.getZCoord()));
118                       g2.draw(rotateShape(line2, o.getActualBearingXZ(),o.getXCoord(),o.getZCoord()));
119                   }
120                 }
121                 //in order to mark a selected wall piece
122                 else if(o instanceof SimWall){
123                   if(((SimWall)o).getSelected()){
124                       g2.setPaint(((SimWall)o).getOutlineColor());
125                       Line2D.Double line1 = new Line2D.Double((int)(o.getXCoord()-o.getWidth()/2),(int)(o.getZCoord()-o.getLength()/2), (int)(o.getXCoord()+o.getWidth()/2), (int)(o.getZCoord()+o.getLength()/2));
126                       Line2D.Double line2 = new Line2D.Double((int)(o.getXCoord()+o.getWidth()/2), (int)(o.getZCoord()-o.getLength()/2),(int)(o.getXCoord()-o.getWidth()/2), (int)(o.getZCoord()+o.getLength()/2));
127                       g2.draw(rotateShape(line1, o.getActualBearingXZ(),o.getXCoord(),o.getZCoord()));
128                       g2.draw(rotateShape(line2, o.getActualBearingXZ(),o.getXCoord(),o.getZCoord()));
129                   }
130                   
131                 }
132                  
133             }
134 
135             //for the LCD purposes
136             if(o instanceof SimRCX){
137 
138                 createLCDDisplay((o.getXCoord()-(o.getWidth()/2)), (o.getZCoord()-(o.getLength()/2)));
139                 //write the LCD output
140                 volImage.createGraphics().drawString(((SimRCX)o).getLCDOutput(),3,16);
141 
142                 java.awt.image.BufferedImage buffImage = volImage.getSnapshot();
143                 double theta=Math.toRadians(o.getActualBearingXZ());
144 
145                 // create a new affine transform rotator
146                 AffineTransform  atx = AffineTransform.getRotateInstance(theta,o.getXCoord()-lcd.getLocation().getX(),o.getZCoord()-lcd.getLocation().getY()); 
147 
148                 java.awt.image.AffineTransformOp transformSetup = new AffineTransformOp(atx,AffineTransformOp.TYPE_BILINEAR);
149 
150                 g2.drawImage(buffImage,transformSetup,(int)(o.getXCoord()-(o.getWidth()/2))+1, (int)(o.getZCoord()-(o.getLength()/2))+10);
151 
152             }
153         }
154     }
155     
156     /** Deligates an appropriate color for a specified object in the simulations.
157      * @param type the string name of the SimObject
158      * @param o the SimObject requiring repaint
159      * @return the corresponding Color
160      */
161     private Color getColorLibrary(String type, SimObject o){
162         int index=1;
163 
164         if(type.equals(shapeNames[0]))index = 0;
165         else if(type.equals(shapeNames[1])) index=1;
166         else if(type.equals(shapeNames[2])) index=2;
167         else if(type.equals(shapeNames[3])) index=3;
168         else if(type.equals(shapeNames[4])) index=4;
169         else if(type.equals(shapeNames[5])) return((SimGround)o).getColor();
170         else if(type.equals(shapeNames[6])) index=5;
171 
172         return this.objectColorArray[index];
173     }
174 
175     /** Sets the color library, sets a color for a specific shape.
176      * @param type shape type
177      * @param color the desired color for that shape
178      */    
179     protected void setColorLibrary(String type, Color color){
180         int index = 1;
181 
182         if(type.equals(shapeNames[0]))index = 0;
183         else if(type.equals(shapeNames[1])) index=1;
184         else if(type.equals(shapeNames[2])) index=2;
185         else if(type.equals(shapeNames[3])) index=3;
186         else if(type.equals(shapeNames[4])) index=4;
187         else if(type.equals(shapeNames[6])) index=5;
188         
189         this.objectColorArray[index]=color;
190         this.repaint();
191     }
192 
193     /**
194     * Checks if there is an associated shape for a SimObject. If so it is 
195     * returned. If not then a standard shape of the SimObject's size is returned.
196     *
197     * @param o the SimObject
198     * @return the appropriate java.awt.Shape
199     */
200     public Shape getShape(SimObject o)
201     {
202             // create a new Shape
203             Shape s;
204 
205             // check the SimObject's type
206             if(o.getType().equalsIgnoreCase("robot"))
207             {
208                     // SimObject is a robot
209                     s=createRobotShape(o.getXCoord(),o.getZCoord(),o.getWidth(),o.getLength());
210             }
211             else if(o.getType().equalsIgnoreCase("light"))
212             {
213                     // SimObject is a light
214                     s=createLightShape(o.getXCoord(),o.getZCoord(),o.getWidth(),o.getLength());
215             }
216             else if(o.getType().equalsIgnoreCase("sensorTouch")||o.getType().equalsIgnoreCase("sensorLight"))
217             {
218                     // SimObject is a sensor
219                     s=createSensorShape(o.getXCoord(),o.getZCoord(),o.getWidth(),o.getLength());
220             }
221             else if (o.getType().equalsIgnoreCase("wall")||o.getType().equalsIgnoreCase("ground")||o.getType().equalsIgnoreCase("road"))
222             {
223                     //SimObject is a wall or ground
224                     s=createWallShape(o.getXCoord(),o.getZCoord(),o.getWidth(),o.getLength());
225             }
226             else
227             {
228                     // unknown SimObject, so create standard shape
229                     s=createStandardShape(o.getXCoord(),o.getZCoord(),o.getWidth(),o.getLength());
230             }
231 
232             // return the shape
233             return s;
234     }
235 
236     /**
237     * Rotates a java.awt.Shape around a certain point a certain angle 
238     *
239     * @param shape the shape to be rotated
240     * @param angle the angle by which the shape is to be rotated
241     * @param X the x co-ordinate about which to rotate
242     * @param Z the z co-ordinate about which to rotate
243     * @return the rotated shape, as a new java.awt.Shape
244     */
245     private Shape rotateShape(Shape shape, double angle, double X, double Z)
246     {
247         // convert the angle to radians
248         double theta=Math.toRadians(angle);
249 
250         // create a new affine transform rotator
251         AffineTransform  atx = AffineTransform.getRotateInstance(theta,X,Z); 
252 
253         // create a rotated version of the shape
254         shape = atx.createTransformedShape(shape);
255 
256         // return the shape
257         return shape;
258     }
259 
260     /**
261     * Creates a robot shape
262     *
263     * @param x the x coordinate of the robot
264     * @param z the z coordinate of the robot
265     * @param width the width of the robot
266     * @param length the length of the robot
267     *
268     * @return the robot shape
269     */
270     private Shape createRobotShape(double x, double z, double width, double length)
271     {
272         // size of the 'wheels'
273         double a=10.0;
274         double b=20.0;
275 
276         // establish top left corner of robot
277         double X=(x-(width/2));
278         double Z=(z-(length/2));
279 
280         // make up the shape
281         Rectangle2D.Double body=new Rectangle2D.Double(X,Z,width,length);
282 
283         Rectangle2D.Double wheel1=new Rectangle2D.Double(X-a-3,Z+5,a,b);
284         Rectangle2D.Double wheel2=new Rectangle2D.Double(X+width+3,Z+5,a,b);
285         Rectangle2D.Double wheel3=new Rectangle2D.Double(X-a+7+(width/2),Z+63,6,b/2);
286                
287         Area shape=new Area(body);
288 
289         shape.add(new Area(wheel1));
290         shape.add(new Area(wheel2));
291         shape.add(new Area(wheel3));
292 
293         // return the complete shape
294         return (Shape) shape;
295     }
296 
297     /** Creates an LCD display on the RCX Brick
298      * @param x the X position of the LCD display
299      * @param z the Z position of the LCD display
300      */
301     private void createLCDDisplay(double x, double z){
302         lcd.setBounds((int)(x+1),(int)(z+10), 38, 20);
303         volImage=lcd.createVolatileImage(38,20);
304         volImage.createGraphics().setColor(Color.black);
305         volImage.createGraphics().drawRect(1,1,36,17);
306 
307     }
308 
309     /** Creates a light shape of the appropriate dimesion.
310      * @param x the X position
311      * @param z the Z position
312      * @param width the width
313      * @param length the length
314      * @return an elipse shape with the set parameters
315      */
316     private Shape createLightShape(double x, double z, double width, double length)
317     {
318         // establish top left corner of object
319         double X=(x-(width/2));
320         double Z=(z-(length/2));
321 
322         return new Ellipse2D.Double(X,Z,width,length);
323     }
324 
325     /** Creates a sensor shape of the appropriate dimension.
326      * @param x the X position
327      * @param z the Z position
328      * @param width the width
329      * @param length the length
330      * @return a rectangle shape with the set parameters
331      */
332     private Shape createSensorShape(double x, double z, double width, double length)
333     {
334         // establish top left corner of object
335         double X=(x-(width/2));
336         double Z=(z-(length/2));
337 
338         return new Rectangle2D.Double(X,Z,width,length);
339     }
340 
341     /** Creates a wall shape of the appropriate dimension
342      * @param x the X position
343      * @param z the Z position
344      * @param width the width
345      * @param length the length
346      * @return a rectangle shape with the set parameters
347      */
348     private Shape createWallShape(double x, double z, double width, double length)
349     {
350         // establish top left corner of object
351         double X=(x-(width/2));
352         double Z=(z-(length/2));
353 
354         return new Rectangle2D.Double(X,Z,width,length);
355     }
356 
357     /** Creates a standard shape, currently a rectangle
358      * @param x the X position
359      * @param z the Z position
360      * @param width the width
361      * @param length the length
362      * @return a rectangle shape with the set parameters
363      */
364     private Shape createStandardShape(double x, double z, double width, double length)
365     {
366         // establish top left corner of object
367         double X=(x-(width/2));
368         double Z=(z-(length/2));
369 
370         return new Rectangle2D.Double(x,z,width,length);
371     }
372 }
373