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.

341 lines
12KB

  1. package de.hems.trafficsim;
  2. import android.os.Bundle;
  3. import android.view.View;
  4. import android.widget.Button;
  5. import android.widget.LinearLayout;
  6. import android.widget.SeekBar;
  7. import android.widget.TextView;
  8. import androidx.appcompat.app.AppCompatActivity;
  9. /**
  10. * Main user interface class, containing all necessary gui elements and their control flow.
  11. */
  12. public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {
  13. /**
  14. * default value of the number of vehicles on the track
  15. */
  16. public static final int defaultNoOfVehicles = 25;
  17. /**
  18. * default value of the length of the track
  19. */
  20. public static final int defaultTrackLength = 100;
  21. /**
  22. * default value of brake probability
  23. */
  24. public static final float defaultBrakeProb = 0.3f;
  25. /**
  26. * default value of the maximum velocity of the vehicles
  27. */
  28. public static final float defaultMaxVelocity = 5.0f;
  29. /**
  30. * default value of the delay between two simulation steps
  31. */
  32. public static final int defaultDelay = 0;
  33. /**
  34. * default value of the number of vehicles on the track
  35. */
  36. public static final int defaultHistoryLength = 50;
  37. /**
  38. * default value of the number of vehicles on the track
  39. */
  40. public static final int defaultFrameskip = 0;
  41. /**
  42. * the track to show in the activity
  43. */
  44. protected Track track;
  45. /**
  46. * the surface view on which the renderer draws the track history
  47. */
  48. protected TimeRecordView trackView;
  49. /**
  50. * the thread which runs the simulation and visualization
  51. */
  52. protected Worker worker;
  53. /**
  54. * the renderer instance drawing the track history
  55. */
  56. protected Renderer renderer;
  57. /**
  58. * the layout which keeps the surface view
  59. */
  60. protected LinearLayout viewStack;
  61. /**
  62. * Utility function to round a float to a given amount of digits.
  63. *
  64. * @param number number to round
  65. * @param digits amount of digits
  66. * @return rounded number
  67. */
  68. public static float round(float number, int digits) {
  69. float div = (float) Math.pow(10.0f, digits);
  70. return Math.round(number * div) / div;
  71. }
  72. /**
  73. * Constructor for MainActivity
  74. *
  75. * @param savedInstanceState Bundle with previously saved activity state, otherwise null
  76. */
  77. @Override
  78. protected void onCreate(Bundle savedInstanceState) {
  79. super.onCreate(savedInstanceState);
  80. setContentView(R.layout.activity_main);
  81. this.track = new Track(defaultNoOfVehicles, defaultTrackLength, defaultBrakeProb,
  82. defaultMaxVelocity, defaultDelay, defaultHistoryLength);
  83. this.viewStack = findViewById(R.id.trackViewStack);
  84. this.trackView = new TimeRecordView(this, track);
  85. viewStack.addView(this.trackView);
  86. this.renderer = new Renderer(track, this.trackView.getHolder());
  87. SeekBar trackLengthSeekBar = findViewById(R.id.trackLengthSeekBar);
  88. trackLengthSeekBar.setOnSeekBarChangeListener(this);
  89. trackLengthSeekBar.setProgress(defaultTrackLength);
  90. ((TextView)(findViewById(R.id.trackLengthTextView))).setText(String.valueOf(defaultTrackLength));
  91. SeekBar maxVelocitySeekBar = findViewById(R.id.maxVelocitySeekBar);
  92. maxVelocitySeekBar.setOnSeekBarChangeListener(this);
  93. maxVelocitySeekBar.setProgress((int)defaultMaxVelocity);
  94. ((TextView)(findViewById(R.id.maxVeloTextView))).setText(String.valueOf((int)defaultMaxVelocity));
  95. SeekBar noOfVehiclesSeekBar = findViewById(R.id.noOfVehiclesSeekBar);
  96. noOfVehiclesSeekBar.setOnSeekBarChangeListener(this);
  97. noOfVehiclesSeekBar.setProgress(defaultNoOfVehicles);
  98. ((TextView)(findViewById(R.id.noOfVehiclesTextView))).setText(String.valueOf(defaultNoOfVehicles));
  99. SeekBar brakeProbabilitySeekBar = findViewById(R.id.brakeProbabilitySeekBar);
  100. brakeProbabilitySeekBar.setOnSeekBarChangeListener(this);
  101. brakeProbabilitySeekBar.setProgress((int)(defaultBrakeProb*20));
  102. ((TextView)(findViewById(R.id.brakeProbTextView))).setText(String.valueOf(defaultBrakeProb));
  103. SeekBar delaySeekBar = findViewById(R.id.simDelaySeekBar);
  104. delaySeekBar.setOnSeekBarChangeListener(this);
  105. delaySeekBar.setProgress(defaultDelay);
  106. ((TextView) (findViewById(R.id.simDelayTextView))).setText(String.valueOf(defaultDelay));
  107. SeekBar frameskipSeekBar = findViewById(R.id.frameskipSeekBar);
  108. frameskipSeekBar.setOnSeekBarChangeListener(this);
  109. frameskipSeekBar.setProgress(defaultFrameskip);
  110. ((TextView) (findViewById(R.id.frameSkipTextView))).setText(String.valueOf(defaultFrameskip));
  111. this.updateStats();
  112. }
  113. /**
  114. * Updates the statistics view.
  115. */
  116. public void updateStats() {
  117. final Track trackRef = this.track;
  118. final TextView lastAvgView = findViewById(R.id.avgVeloLastView);
  119. final TextView overallAvgView = findViewById(R.id.avgVeloOverallView);
  120. final TextView delayedAvgView = findViewById(R.id.delayedAvgTextView);
  121. final TextView stepsView = findViewById(R.id.stepsTextView);
  122. runOnUiThread(new Runnable() {
  123. @Override
  124. public void run() {
  125. lastAvgView.setText(String.valueOf(round(trackRef.getLastAvg(), 2)));
  126. overallAvgView.setText(String.valueOf(round(trackRef.getOverallAvg(), 2)));
  127. stepsView.setText(String.valueOf(trackRef.getSteps()));
  128. delayedAvgView.setText(String.valueOf(round(trackRef.getDelayedAvg(), 2)));
  129. }
  130. });
  131. }
  132. /**
  133. * Handler function for clicks on the "Step" button.
  134. *
  135. * @param view the view the event is generated from
  136. */
  137. public void onStepButtonClick(View view) {
  138. this.track.timeElapse();
  139. this.updateStats();
  140. this.renderer.draw();
  141. }
  142. /**
  143. * Handler function for clicks on the "Play" button.
  144. *
  145. * @param view the view the event is generated from
  146. */
  147. public void onPlayButtonClick(View view) {
  148. Button playButton = findViewById(R.id.playButton);
  149. playButton.setEnabled(false);
  150. Button stepButton = findViewById(R.id.stepButton);
  151. stepButton.setEnabled(false);
  152. Button stopButton = findViewById(R.id.stopButton);
  153. stopButton.setEnabled(true);
  154. Button clearButton = findViewById(R.id.clearButton);
  155. clearButton.setEnabled(false);
  156. int frameskip = ((SeekBar) (findViewById(R.id.frameskipSeekBar))).getProgress();
  157. this.worker = new Worker(track, this, renderer, frameskip);
  158. this.worker.start();
  159. }
  160. /**
  161. * Handler function for clicks on the "Stop" button.
  162. *
  163. * @param view the view the event is generated from
  164. */
  165. public void onStopButtonClick(View view) {
  166. Button playButton = findViewById(R.id.playButton);
  167. playButton.setEnabled(true);
  168. Button stepButton = findViewById(R.id.stepButton);
  169. stepButton.setEnabled(true);
  170. Button stopButton = findViewById(R.id.stopButton);
  171. stopButton.setEnabled(false);
  172. Button clearButton = findViewById(R.id.clearButton);
  173. clearButton.setEnabled(true);
  174. this.stopWorker();
  175. this.worker = null;
  176. }
  177. /**
  178. * Stops the current worker thread.
  179. */
  180. protected void stopWorker() {
  181. this.worker.setStop(true);
  182. try {
  183. this.worker.join();
  184. } catch (InterruptedException ex) {
  185. }
  186. this.worker = null;
  187. }
  188. /**
  189. * Handler function for clicks on the "Stop" button.
  190. *
  191. * @param view the view the event is generated from
  192. */
  193. public void onClearButtonClick(View view) {
  194. if (this.worker != null) { // There was a simulation running
  195. this.stopWorker();
  196. }
  197. Button playButton = findViewById(R.id.playButton);
  198. playButton.setEnabled(true);
  199. Button stepButton = findViewById(R.id.stepButton);
  200. stepButton.setEnabled(true);
  201. Button stopButton = findViewById(R.id.stopButton);
  202. stopButton.setEnabled(false);
  203. this.updateTrack();
  204. this.updateStats();
  205. this.renderer.draw();
  206. }
  207. /**
  208. * Creates a new track with the current settings. This methods restarts the simulation it
  209. * it was running before.
  210. */
  211. protected void updateTrack() {
  212. int newTrackLength = ((SeekBar) (findViewById(R.id.trackLengthSeekBar))).getProgress();
  213. SeekBar noOfVehiclesSeekBar = findViewById(R.id.noOfVehiclesSeekBar);
  214. int newNoOfVehicles = noOfVehiclesSeekBar.getProgress();
  215. if (newTrackLength < newNoOfVehicles) { // Dont allow values greater than track length!
  216. newNoOfVehicles = newTrackLength;
  217. noOfVehiclesSeekBar.setProgress(newNoOfVehicles);
  218. }
  219. TextView noOfVehiclesTextView = findViewById(R.id.noOfVehiclesTextView);
  220. noOfVehiclesTextView.setText(String.valueOf(newNoOfVehicles));
  221. TextView trackLengthTextView = findViewById(R.id.trackLengthTextView);
  222. trackLengthTextView.setText(String.valueOf(newTrackLength));
  223. float newMaxVelocity = ((SeekBar) findViewById(R.id.maxVelocitySeekBar)).getProgress();
  224. SeekBar brakeProbabilitySeekBar = findViewById(R.id.brakeProbabilitySeekBar);
  225. float newBrakeProb = (float) brakeProbabilitySeekBar.getProgress()
  226. / (float)brakeProbabilitySeekBar.getMax();
  227. int newDelay = ((SeekBar)(findViewById(R.id.simDelaySeekBar))).getProgress();
  228. int newFrameskip = ((SeekBar)(findViewById(R.id.frameskipSeekBar))).getProgress();
  229. boolean wasRunning = this.worker != null;
  230. if (wasRunning) {
  231. this.worker.setStop(true);
  232. try {
  233. this.worker.join();
  234. } catch (InterruptedException ex) {
  235. }
  236. }
  237. this.track = new Track(newNoOfVehicles, newTrackLength, newBrakeProb, newMaxVelocity,
  238. newDelay, defaultHistoryLength);
  239. this.renderer.setTrack(this.track);
  240. if (wasRunning) {
  241. this.worker = new Worker(track, this, renderer, newFrameskip);
  242. this.worker.start();
  243. }
  244. }
  245. /**
  246. * Handler function for changes on the seek bars.
  247. *
  248. * @param seekBar the seek bar changed
  249. * @param progress the new progress value of the seek bar
  250. * @param fromUser flag if the event is the result of an user action
  251. */
  252. @Override
  253. public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
  254. if (seekBar == findViewById(R.id.noOfVehiclesSeekBar)) {
  255. this.updateTrack();
  256. } else if (seekBar == findViewById(R.id.brakeProbabilitySeekBar)) {
  257. float newBrakeProb = (float) seekBar.getProgress() / (float) seekBar.getMax();
  258. this.track.setBrakeProb(newBrakeProb);
  259. TextView newBrakeProbTextView = findViewById(R.id.brakeProbTextView);
  260. newBrakeProbTextView.setText(String.valueOf((newBrakeProb)));
  261. } else if (seekBar == findViewById(R.id.maxVelocitySeekBar)) {
  262. this.track.setMaxVelocity(seekBar.getProgress());
  263. TextView tv = findViewById(R.id.maxVeloTextView);
  264. tv.setText(String.valueOf(progress));
  265. } else if (seekBar == findViewById(R.id.trackLengthSeekBar)) {
  266. this.updateTrack();
  267. } else if (seekBar == findViewById(R.id.simDelaySeekBar)) {
  268. TextView tv = findViewById(R.id.simDelayTextView);
  269. tv.setText(String.valueOf(seekBar.getProgress()));
  270. this.track.setWaitTime(seekBar.getProgress());
  271. } else if (seekBar == findViewById(R.id.frameskipSeekBar)) {
  272. TextView tv = findViewById(R.id.frameSkipTextView);
  273. tv.setText(String.valueOf(seekBar.getProgress()));
  274. if (this.worker != null) {
  275. this.worker.setFrameskip(seekBar.getProgress());
  276. }
  277. }
  278. }
  279. /**
  280. * Handler function for beginning touch events on a seek bar.
  281. *
  282. * @param seekBar the seek bar touched
  283. */
  284. @Override
  285. public void onStartTrackingTouch(SeekBar seekBar) {
  286. }
  287. /**
  288. * Handler function for ending touch events on a seek bar.
  289. *
  290. * @param seekBar the seek bar touched
  291. */
  292. @Override
  293. public void onStopTrackingTouch(SeekBar seekBar) {
  294. }
  295. }