TrafficSim/app/src/main/java/de/hems/trafficsim/Renderer.java
2020-11-15 16:30:41 +01:00

183 行
6.3 KiB
Java

package de.hems.trafficsim;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.SurfaceHolder;
import java.util.ConcurrentModificationException;
import java.util.List;
/**
* User interface class rendering the track history on a SurfaceView.
*/
public class Renderer {
/**
* the track to render
*/
protected Track track;
/**
* width of a rectangle representing one vehicle
*/
protected int pixelPerVehicle;
/**
* height of a rectangle representing one vehicle
*/
protected int pixelPerLine;
/**
* amount of pixels per track position which are lost by rounding
*/
protected float tooShortPerTrackLength;
/**
* amount of pixels per height which are lost by rounding
*/
protected float tooShortPerHeight;
/**
* Paint instance of the renderer
*/
protected Paint paint;
/**
* holder of the surface the renderer draws to
*/
protected SurfaceHolder holder;
/**
* width of the surface to draw to
*/
protected int width;
/**
* height of the surface to draw to
*/
protected int height;
/**
* temporary reference to the time records of one simulation step
*/
private List<VehicleTimeRecord> stepRecords;
/**
* temporary reference to the canvas to draw to
*/
private Canvas canvas;
/**
* Constuctor for a Renderer.
*
* @param track the track to render
* @param holder the holder of the surface to draw to
*/
public Renderer(Track track, SurfaceHolder holder) {
this.track = track;
this.holder = holder;
this.paint = new Paint();
}
/**
* Updates the dimension information of the renderer.
*
* @param width the width of the SurfaceView
* @param height the height of the SurfaceView
*/
public void setSize(int width, int height) {
if (width > 0 && height > 0) {
this.pixelPerVehicle = width / (int) this.track.getTrackLength();
this.tooShortPerTrackLength =
(width - this.pixelPerVehicle * this.track.getTrackLength())
/ this.track.getTrackLength();
this.pixelPerLine = height / this.track.getHistoryLength();
this.tooShortPerHeight = (height - this.pixelPerLine * this.track.getHistoryLength())
/ (float) height;
System.out.println("Viewport: " + width + "x" + height);
this.width = width;
this.height = height;
}
}
/**
* Updates the track of the Surface.
*
* @param track the new track to render
*/
public void setTrack(Track track) {
this.track = track;
this.setSize(width, height);
}
/**
* Utility function which calculates a color from the relation between the current speed of a
* vehicle and it's maximum speed (from red over yellow to green).
*
* @param curVelocity current velocity of the vehicle
* @param maxVelocity maximum velocity of the vehilce
* @return color encoded as Android color integer
*/
protected int getColor(float curVelocity, float maxVelocity) {
float perc = curVelocity / maxVelocity;
perc = 1 - perc;
if (perc <= 0.5) {
int red = ((int) (2 * perc * 0xFF)) << 16;
int green = 0xFF << 8;
int blue = 0;
return 0xff000000 | red | green | blue;
} else {
int red = 0xFF << 16;
int green = ((int) (0xFF - 0xFF * (perc - 0.5) * 2)) << 8;
int blue = 0;
return 0xff000000 | red | green | blue;
}
}
/**
* Draws the current state of the track history to the Surface.
*/
protected void draw() {
try {
if (this.pixelPerVehicle == 0) {
Rect rect = this.holder.getSurfaceFrame();
this.setSize(rect.right, rect.bottom);
}
canvas = this.holder.lockCanvas();
synchronized (holder) {
int y = 0;
int left = 0;
int hCompensateStart = 0;
int hCompensateEnd = 0;
int vCompensateStart = 0;
int vCompensateEnd = 0;
canvas.drawColor(Color.BLACK);
for (int curStepIdx = this.track.getVtrList().size()-1; curStepIdx >= 0;
curStepIdx--) {
try {
try {
track.getListSemaphore().acquire();
} catch (InterruptedException ex) {
return;
}
vCompensateStart = Math.round(y * this.tooShortPerHeight);
vCompensateEnd = Math.round((y+this.pixelPerLine) * this.tooShortPerHeight);
stepRecords = this.track.getVtrList().get(curStepIdx);
int i = 0;
for (VehicleTimeRecord r : stepRecords) {
left = (int) (this.pixelPerVehicle * r.getPosition());
hCompensateStart = Math.round(r.getPosition() * this.tooShortPerTrackLength);
hCompensateEnd = Math.round((r.getPosition() + this.pixelPerVehicle) * this.tooShortPerTrackLength);
this.paint.setColor(getColor(r.getVelocity(), r.getMaxVelocity()));
canvas.drawRect(left + hCompensateStart, y+vCompensateStart,
left + this.pixelPerVehicle + hCompensateEnd,
y + pixelPerLine + vCompensateEnd, this.paint);
i++;
}
track.getListSemaphore().release();
y += pixelPerLine;
} catch (ConcurrentModificationException ex) {
System.out.println("Concurrent Exception occured, skipping record");
y += pixelPerLine;
}
}
}
} finally {
if (canvas != null) {
this.holder.unlockCanvasAndPost(canvas);
}
}
}
}