You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
6.3KB

  1. package de.hems.trafficsim;
  2. import android.graphics.Canvas;
  3. import android.graphics.Color;
  4. import android.graphics.Paint;
  5. import android.graphics.Rect;
  6. import android.view.SurfaceHolder;
  7. import java.util.ConcurrentModificationException;
  8. import java.util.List;
  9. /**
  10. * User interface class rendering the track history on a SurfaceView.
  11. */
  12. public class Renderer {
  13. /**
  14. * the track to render
  15. */
  16. protected Track track;
  17. /**
  18. * width of a rectangle representing one vehicle
  19. */
  20. protected int pixelPerVehicle;
  21. /**
  22. * height of a rectangle representing one vehicle
  23. */
  24. protected int pixelPerLine;
  25. /**
  26. * amount of pixels per track position which are lost by rounding
  27. */
  28. protected float tooShortPerTrackLength;
  29. /**
  30. * amount of pixels per height which are lost by rounding
  31. */
  32. protected float tooShortPerHeight;
  33. /**
  34. * Paint instance of the renderer
  35. */
  36. protected Paint paint;
  37. /**
  38. * holder of the surface the renderer draws to
  39. */
  40. protected SurfaceHolder holder;
  41. /**
  42. * width of the surface to draw to
  43. */
  44. protected int width;
  45. /**
  46. * height of the surface to draw to
  47. */
  48. protected int height;
  49. /**
  50. * temporary reference to the time records of one simulation step
  51. */
  52. private List<VehicleTimeRecord> stepRecords;
  53. /**
  54. * temporary reference to the canvas to draw to
  55. */
  56. private Canvas canvas;
  57. /**
  58. * Constuctor for a Renderer.
  59. *
  60. * @param track the track to render
  61. * @param holder the holder of the surface to draw to
  62. */
  63. public Renderer(Track track, SurfaceHolder holder) {
  64. this.track = track;
  65. this.holder = holder;
  66. this.paint = new Paint();
  67. }
  68. /**
  69. * Updates the dimension information of the renderer.
  70. *
  71. * @param width the width of the SurfaceView
  72. * @param height the height of the SurfaceView
  73. */
  74. public void setSize(int width, int height) {
  75. if (width > 0 && height > 0) {
  76. this.pixelPerVehicle = width / (int) this.track.getTrackLength();
  77. this.tooShortPerTrackLength =
  78. (width - this.pixelPerVehicle * this.track.getTrackLength())
  79. / this.track.getTrackLength();
  80. this.pixelPerLine = height / this.track.getHistoryLength();
  81. this.tooShortPerHeight = (height - this.pixelPerLine * this.track.getHistoryLength())
  82. / (float) height;
  83. System.out.println("Viewport: " + width + "x" + height);
  84. this.width = width;
  85. this.height = height;
  86. }
  87. }
  88. /**
  89. * Updates the track of the Surface.
  90. *
  91. * @param track the new track to render
  92. */
  93. public void setTrack(Track track) {
  94. this.track = track;
  95. this.setSize(width, height);
  96. }
  97. /**
  98. * Utility function which calculates a color from the relation between the current speed of a
  99. * vehicle and it's maximum speed (from red over yellow to green).
  100. *
  101. * @param curVelocity current velocity of the vehicle
  102. * @param maxVelocity maximum velocity of the vehilce
  103. * @return color encoded as Android color integer
  104. */
  105. protected int getColor(float curVelocity, float maxVelocity) {
  106. float perc = curVelocity / maxVelocity;
  107. perc = 1 - perc;
  108. if (perc <= 0.5) {
  109. int red = ((int) (2 * perc * 0xFF)) << 16;
  110. int green = 0xFF << 8;
  111. int blue = 0;
  112. return 0xff000000 | red | green | blue;
  113. } else {
  114. int red = 0xFF << 16;
  115. int green = ((int) (0xFF - 0xFF * (perc - 0.5) * 2)) << 8;
  116. int blue = 0;
  117. return 0xff000000 | red | green | blue;
  118. }
  119. }
  120. /**
  121. * Draws the current state of the track history to the Surface.
  122. */
  123. protected void draw() {
  124. try {
  125. if (this.pixelPerVehicle == 0) {
  126. Rect rect = this.holder.getSurfaceFrame();
  127. this.setSize(rect.right, rect.bottom);
  128. }
  129. canvas = this.holder.lockCanvas();
  130. synchronized (holder) {
  131. int y = 0;
  132. int left = 0;
  133. int hCompensateStart = 0;
  134. int hCompensateEnd = 0;
  135. int vCompensateStart = 0;
  136. int vCompensateEnd = 0;
  137. canvas.drawColor(Color.BLACK);
  138. for (int curStepIdx = this.track.getVtrList().size()-1; curStepIdx >= 0;
  139. curStepIdx--) {
  140. try {
  141. try {
  142. track.getListSemaphore().acquire();
  143. } catch (InterruptedException ex) {
  144. return;
  145. }
  146. vCompensateStart = Math.round(y * this.tooShortPerHeight);
  147. vCompensateEnd = Math.round((y+this.pixelPerLine) * this.tooShortPerHeight);
  148. stepRecords = this.track.getVtrList().get(curStepIdx);
  149. int i = 0;
  150. for (VehicleTimeRecord r : stepRecords) {
  151. left = (int) (this.pixelPerVehicle * r.getPosition());
  152. hCompensateStart = Math.round(r.getPosition() * this.tooShortPerTrackLength);
  153. hCompensateEnd = Math.round((r.getPosition() + this.pixelPerVehicle) * this.tooShortPerTrackLength);
  154. this.paint.setColor(getColor(r.getVelocity(), r.getMaxVelocity()));
  155. canvas.drawRect(left + hCompensateStart, y+vCompensateStart,
  156. left + this.pixelPerVehicle + hCompensateEnd,
  157. y + pixelPerLine + vCompensateEnd, this.paint);
  158. i++;
  159. }
  160. track.getListSemaphore().release();
  161. y += pixelPerLine;
  162. } catch (ConcurrentModificationException ex) {
  163. System.out.println("Concurrent Exception occured, skipping record");
  164. y += pixelPerLine;
  165. }
  166. }
  167. }
  168. } finally {
  169. if (canvas != null) {
  170. this.holder.unlockCanvasAndPost(canvas);
  171. }
  172. }
  173. }
  174. }