/*
* Datei: VideoPlugin.java
* Autor(en): Lukas König
* Java-Version: 6.0
* Erstellt: 23.04.2010
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.plugins.standard.visualization;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingUtilities;
import eas.math.geometry.Polygon2D;
import eas.math.geometry.Rectangle2D;
import eas.math.geometry.Vector2D;
import eas.miscellaneous.StaticMethods;
import eas.plugins.AbstractDefaultPlugin;
import eas.simulation.Wink;
import eas.simulation.agent.AbstractAgent;
import eas.simulation.agent.Evolvable;
import eas.simulation.event.EASEvent;
import eas.simulation.spatial.sim2D.gridSimulation.standardEnvironments.AbstractGridEnvironment;
import eas.simulation.spatial.sim2D.gridSimulation.standardGridObjects.GridObject;
import eas.simulation.spatial.sim2D.standardAgents.AbstractAgent2D;
import eas.simulation.spatial.sim2D.standardEnvironments.AbstractEnvironment2D;
import eas.simulation.standardEnvironments.AbstractEnvironment;
import eas.startSetup.ParCollection;
import eas.startSetup.SingleParameter;
import eas.startSetup.parameterDatatypes.Datatypes;
import eas.videoRecording.avi.AVIOutputStream;
import eas.videoRecording.gif.SimpleGIF;
/**
* Implementiert ein Plugin zur Anzeige eines Simulationslaufs bzw. zur
* Erzeugung von AVI- und GIF-Videos aus einem Simulationslauf.
*
* @author Lukas König
*/
public class AllroundVideoPlugin extends AbstractDefaultPlugin<AbstractEnvironment<AbstractAgent<?>>> {
private static final long serialVersionUID = 7976142351744745219L;
private long liveCyc;
/**
* The actual liveFilm parameter.
*/
private boolean liveFilm;
/**
* The live Window the live film is shown in.
*/
private LiveWindow liveWindow;
public LiveWindow getLiveWindow() {
return this.liveWindow;
}
/**
* Die Nummer der aktuellen AVI-Datei.
*/
private int filmNumAVI = 0;
/**
* Die Nummer der aktuellen AVI-Datei.
*/
private int filmNumGIF = 0;
/**
* Der Outputstream für den AVI-Film.
*/
private AVIOutputStream AVIout;
/**
* Abfolge von Bildern des Simulationsfeldes für die GIF-Speicherung.
*/
private transient LinkedList<BufferedImage> bilder;
/**
* Überschriebener Konstruktor.
*/
public AllroundVideoPlugin() {
this.bilder = new LinkedList<BufferedImage>();
}
/**
* Parametername für das Zusatzbild.
*/
public static final String ZUSATZ_BILD_PAR = "showAdditionalAgentInformation";
/**
* Parameter name for live films.
*/
public static final String LIVE_FILM_PAR = "livefilm?";
/**
* Parametername für die GIF-Datei.
*/
public static final String GIF_DATEI_PAR = "giffile";
private int aviDimWidth;
private int aviDimHeight;
/**
* Die generischen Parameter beziehen sich auf Dateinamen und
* Bildwiederholraten der Videos, die im GIF- bzw. AVI-Format gespeichert
* werden.
*
* @return Liste der Parameter.
*/
@Override
public List<SingleParameter> getParameters() {
ArrayList<SingleParameter> liste = new ArrayList<SingleParameter>();
liste.add(new SingleParameter(
AllroundVideoPlugin.GIF_DATEI_PAR,
Datatypes.STRING,
"null",
"Der Name der zu erzeugenden GIF-Datei ohne Endung (null, "
+ "falls keine GIF-Datei erzeugt werden soll).",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"avifile",
Datatypes.STRING,
"null",
"Der Name der zu erzeugenden AVI-Datei ohne Endung (null, "
+ "falls keine AVI-Datei erzeugt werden soll).",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"aviwidth",
Datatypes.integerRange(1, 1600),
1024,
"Constant width of the AVI-film.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"aviheight",
Datatypes.integerRange(1, 1280),
768,
"Constant height of the AVI-film.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"aviStoreEveryXCycles",
Datatypes.LONG,
5l,
"Anzahl von Zyklen von einem zum nächsten zu speichernden "
+ "Bild des AVI-Films.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"gifStoreEveryXCycles",
Datatypes.LONG,
5l,
"Anzahl von Zyklen von einem zum nächsten zu speichernden "
+ "Bild des GIF-Films.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"aviImagesPerFile",
Datatypes.LONG,
5000l,
"Anzahl von Zyklen, nach denen eine AVI-Datei abgeschlossen "
+ "und ein neuer Film begonnen wird.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"gifImagesPerFile",
Datatypes.LONG,
500l,
"Anzahl von Zyklen, nach denen eine GIF-Datei abgeschlossen "
+ "und ein neuer Film begonnen wird.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
AllroundVideoPlugin.ZUSATZ_BILD_PAR,
Datatypes.fixedStringSet(new String[] {
"best",
"null",
"extern",
"agent:0",
"agent:1",
"agent:2",
"agent:3",
"agent:4",
"agent:5",
"agent:6",
"agent:7",
"agent:8",
"agent:9",
"agent:10"}),
"best",
"Modus für Anzeigen eines zusätzlichen Bildes neben dem Feld ("
+ "best, agent:*int* (Automaten), null, extern)",
this.id().toUpperCase()));
liste.add(new SingleParameter(
AllroundVideoPlugin.LIVE_FILM_PAR,
Datatypes.BOOLEAN,
true,
"If a live simulation visualization is "
+ "shown during simulation.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"framesPerSecond",
Datatypes.DOUBLE,
50d,
"Corresponds to ticks per second in AVI film.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"closeWindowsFramesOnTermination",
Datatypes.BOOLEAN,
false,
"If the frame windows should be closed when the simulation terminates.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
"ShowInsideViewOfMarked",
Datatypes.BOOLEAN,
true,
"Shows the inside view of the marked agent.",
this.id().toUpperCase()));
liste.add(new SingleParameter(
ROTATION_SPEED_PAR_NAME,
Datatypes.DOUBLE,
0.005,
"The maximum rotation speed (in RAD) of the camera when visualization is in following mode (set to >= 7 for immediate rotation to agent angle).",
this.id().toUpperCase(),
this.getClass()));
liste.add(new SingleParameter(
TRANSLATION_ACC_PAR_NAME,
Datatypes.DOUBLE,
0.01,
"The value the translation speed of the camera is accelerated when visualization is in following mode (set to positive infinity for unsmooth following).",
this.id().toUpperCase(),
this.getClass()));
return liste;
}
public static final String ROTATION_SPEED_PAR_NAME = "cameraRotationSpeedForFollowingAgent";
public static final String TRANSLATION_ACC_PAR_NAME = "cameraTranslationAcceleration";
private static double cameraRotationSpeedForFollowingAgent = 0;
private static double cameraTranslationAcceleration = 0;
public static void setCameraRotationSpeedForFollowingAgent(
double cameraRotationSpeedForFollowingAgent) {
AllroundVideoPlugin.cameraRotationSpeedForFollowingAgent = cameraRotationSpeedForFollowingAgent;
}
public static void setCameraTranslationAcceleration(
double cameraTranslationAcceleration) {
AllroundVideoPlugin.cameraTranslationAcceleration = cameraTranslationAcceleration;
}
/**
* @return The id of this plugin.
*/
@Override
public String id() {
return AbstractDefaultPlugin.ALLROUND_PLUGIN_PREFIX + "-videoplugin";
}
/**
* Der konstante Modus "bester": der beste Roboter wird
* neben dem Feld angezeigt.
*/
public static final String MODUS_BESTER = "best";
/**
* Der konstante Modus "einzelRoboter": ein bestimmter Roboter wird
* neben dem Feld angezeigt. Benutzung: "agent:*num*"
*/
public static final String MODUS_EINZELROB = "agent";
/**
* Der konstante Modus extern ("extern"): Es wird das lokal in VideoPlugin
* gespeicherte von außen setzbare Bild neben dem Feld angezeigt.
*/
public static final String MODUS_EXTERN = "extern";
/**
* @param agents A list of agents.
* @param params The parameters.
*
* @return The best of the evolvable agents in the list, <code>null</code>
* if none of the agents is evolvable.
*/
private AbstractAgent<?> bester(
final List<AbstractAgent<?>> agents) {
AbstractAgent<?> bester = null;
Evolvable<?> akt = null;
double bestFit = Double.NEGATIVE_INFINITY;
for (int i = 0; i < agents.size(); i++) {
AbstractAgent<?> a = agents.get(i);
if (this.isEvolvable(a)) {
akt = (Evolvable<?>) a;
if (akt.getEvaluation() > bestFit) {
bester = akt.getThisEvolvableAgent();
bestFit = akt.getEvaluation();
}
}
}
return bester;
}
/**
* @param img An image.
* @return A copy of the image.
*/
private BufferedImage copy(final BufferedImage img) {
if (img == null) {
return null;
}
BufferedImage copy = new BufferedImage(img.getWidth(), img.getHeight(),
img.getType());
copy.createGraphics().drawImage(img, 0, 0, null);
return copy;
}
private Color selectedColor = new Color(255, 180, 180, 0);
public Integer getMarkedAgentId() {
return this.markedAgentId;
}
/**
* @param str Ein zu setzender String.
* @param env Die Umgebung, in der sich das zu zeichnende Feld
* befindet.
* @param params Der Parametersatz.
*
* @return Das BufferedImage des Feldes.
*/
@SuppressWarnings({ "rawtypes" })
private BufferedImage erzeugeFeldBild(
// final String[] str,
final AbstractEnvironment<AbstractAgent<?>> env,
final ParCollection params) {
BufferedImage buffImgFeld = this.copy(env.getOutsideView()); // TODO - this is inefficient.
// BufferedImage buffImgFeld = env.getOutsideView();
Graphics2D g = buffImgFeld.createGraphics();
try {
Rectangle2D rect;
rect = ((AbstractEnvironment2D) env).getClippingRectangle();
g.setClip(
(int) rect.upperLeftCorner().x,
(int) rect.upperLeftCorner().y,
(int) (rect.upperLeftCorner().x + rect.getWidth()),
(int) (rect.upperLeftCorner().y + rect.getHeight()));
} catch (Exception e1) {
}
AbstractAgent bester = this.bester(env.getAgents());
int radius = 20;
String zusatzAnzeigeModus = (String) params
.getParValue(AllroundVideoPlugin.ZUSATZ_BILD_PAR);
if (this.markedAgentId != null) {
bester = env.getAgent(this.markedAgentId);
}
if (zusatzAnzeigeModus.equalsIgnoreCase(
AllroundVideoPlugin.MODUS_BESTER) && bester != null) {
g.setColor(Color.red);
g.setStroke(new BasicStroke(
4,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
try {
g.setColor(Color.red);
double height = 25;
double width = 25;
Vector2D agPos = ((AbstractEnvironment2D) this.currentEnv).getPointInVisualization(((AbstractEnvironment2D) this.currentEnv).getAgentPosition(this.markedAgentId));
agPos.sub(new Vector2D(width / 2, height / 2));
g.drawOval((int) agPos.x, (int) agPos.y, (int) (width), (int) (height));
Polygon2D pol2D = ((AbstractEnvironment2D) this.currentEnv).getAgentShapeInVisualization(this.markedAgentId);
Polygon pol = pol2D.toPol();
g.setColor(Color.red);
g.drawPolygon(pol);
} catch (Exception e) {
try {
g.drawOval(
(int) env.getPositionInVisualization(bester.id()).x - radius / 2,
(int) env.getPositionInVisualization(bester.id()).y - radius / 2,
radius,
radius);
} catch (Exception e1) {}
}
} else if (zusatzAnzeigeModus.startsWith(
AllroundVideoPlugin.MODUS_EINZELROB)) {
int num = Integer.parseInt(
zusatzAnzeigeModus.split(":")[1]);
if (this.markedAgentId != null) {
num = this.markedAgentId;
}
g.setColor(Color.red);
g.setStroke(new BasicStroke(
4,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
int xMitte = 0;
int yMitte = 0;
try {
xMitte = (int) env.getPositionInVisualization(num).x - radius / 2;
yMitte = (int) env.getPositionInVisualization(num).y - radius / 2;
} catch (final Exception e) {
StaticMethods.log(
StaticMethods.LOG_STAGE1,
"Agent " + num + " cannot be selected.",
params);
}
try {
Polygon pol = ((AbstractEnvironment2D) this.currentEnv).getAgentShapeInVisualization(this.markedAgentId).toPol();
g.setColor(this.selectedColor);
g.fillPolygon(pol);
g.setColor(Color.red);
g.drawPolygon(pol);
} catch (Exception e) {
g.drawOval(
xMitte,
yMitte,
radius,
radius);
}
}
// Feld beschriften.
// for (int i = 0; i < str.length; i++) {
// Color bckGrnd = Color.white;
// try {
// bckGrnd = ((AbstractEnvironment2D) this.environment).getBackgroundColor();
// } catch (Exception e) {
// }
// g.setColor(bckGrnd);
// g.fillRect(10, 10 + 15 * i, 100, 11 + 15 * i);
// g.setColor(Color.BLUE);
// g.drawString(str[i], 10, 20 + 15 * i);
// }
return buffImgFeld;
}
// private Color redWeak = new Color(255, 0, 100, 200);
private boolean isEvolvable(AbstractAgent<?> a) {
return Evolvable.class.isAssignableFrom(a.getClass());
}
/**
* Erzeugt ein zusätzlich zum Feld anzuzeigendes Bild. Das kann ein Automat
* oder eine sonstige grafische Darstellung des Simulationsverlaufs sein.
*
* @param umg Die Umgebung, in der sich das zu zeichnende Feld
* befindet.
* @param params Der Parametersatz.
*
* @return Das BufferedImage des Automaten.
*/
private BufferedImage erzeugeAutBild(
final AbstractEnvironment<AbstractAgent<?>> umg,
final ParCollection params) {
AbstractAgent<?> bester = this.bester(umg.getAgents());
AbstractAgent<?> realBest = bester;
BufferedImage buffImgAut = null;
Graphics2D g;
String zusatzAnzeigeModus = (String) params
.getParValue(AllroundVideoPlugin.ZUSATZ_BILD_PAR);
if (zusatzAnzeigeModus.equalsIgnoreCase(
AllroundVideoPlugin.MODUS_BESTER)
|| zusatzAnzeigeModus.startsWith(
AllroundVideoPlugin.MODUS_EINZELROB)) {
if (zusatzAnzeigeModus.startsWith(
AllroundVideoPlugin.MODUS_EINZELROB)) {
int num = Integer.parseInt(
zusatzAnzeigeModus.split(":")[1]);
try {
bester = umg.getAgents().get(num);
} catch (final Exception e) {
StaticMethods.log(
StaticMethods.LOG_STAGE1,
"Agent " + num + " cannot be selected.",
params);
}
}
if (this.markedAgentId != null) {
AbstractAgent<?> marked = umg.getAgent(this.markedAgentId);
bester = marked;
}
if (bester == null) {
return null;
}
// buffImgAut = this.copy(bester.getInsideView());
buffImgAut = bester.getInsideView();
g = buffImgAut.createGraphics();
g.setColor(Color.black);
String evol = "";
if (this.isEvolvable(bester)) {
evol = " ("
+ ((Evolvable<?>) bester).getEvaluation()
+ ")";
}
if (realBest == bester) {
g.drawString(
bester.getClass().getSimpleName() + " (best): "
+ bester.id()
+ evol,
10,
20);
} else {
g.drawString(
bester.getClass().getSimpleName() + ": "
+ bester.id()
+ evol,
10,
20);
}
} else if (zusatzAnzeigeModus.equalsIgnoreCase(
AllroundVideoPlugin.MODUS_EXTERN)) {
return this.darBild;
}
return buffImgAut;
}
private transient BufferedImage autImgStored;
/**
* Mit dem Feld bei Filmerzeugung darzustellendes Bild.
*/
private transient BufferedImage darBild;
/**
* @return Returns the darBild.
*/
public BufferedImage getDarBild() {
return this.darBild;
}
/**
* @param bild The darBild to set.
*/
public void setDarBild(final BufferedImage bild) {
// this.darBild = this.copy(bild);
this.darBild = bild;
}
/**
* Gibt ein Bild des aktuellen Feldes zurück.
*
* @param str Links oben zu setzende Strings.
* @param umg Die Umgebung, in der sich das zu zeichnende Feld
* befindet.
* @param params Der Parametersatz.
*
* @return Ein Bild des aktuellen Feldes.
*/
public BufferedImage erzeugeBild(
// final String[] str,
final AbstractEnvironment<AbstractAgent<?>> umg,
final ParCollection params) {
Graphics2D g;
BufferedImage gesamtImg, autImg, feldImg;
feldImg = this.erzeugeFeldBild(umg, params);
if (params.getParValueBoolean("ShowInsideViewOfMarked")) {
autImg = this.erzeugeAutBild(umg, params);
} else {
autImg = null;
}
this.autImgStored = autImg;
if (feldImg == null) {
return autImg;
}
if (autImg == null) {
return feldImg;
}
gesamtImg = new BufferedImage(
feldImg.getWidth() + autImg.getWidth(),
Math.max(feldImg.getHeight(), autImg.getHeight()),
BufferedImage.TYPE_INT_RGB);
g = gesamtImg.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, gesamtImg.getWidth() - 1, gesamtImg.getHeight() - 1);
g.drawImage(
feldImg,
0,
0,
feldImg.getWidth(),
feldImg.getHeight(),
null);
g.drawImage(
autImg,
feldImg.getWidth(),
0,
autImg.getWidth(),
autImg.getHeight(),
null);
g.setColor(Color.black);
g.drawRect(0, 0, gesamtImg.getWidth() - 1, gesamtImg.getHeight() - 1);
return gesamtImg;
}
/**
* fügt eine Abblidung des aktuellen Feldes zur AVI-Datei hinzu.
*
* @param datNam Der Name der AVI-Datei.
* @param simZyk Die Simulationszyklen.
* @param umg Die Umgebung, in der sich das zu zeichnende Feld
* befindet.
* @param params Der Parametersatz.
*/
private void aviFrameHinzufuegen(
final String datNam,
final AbstractEnvironment<AbstractAgent<?>> umg,
final ParCollection params) {
long bildIntAVI = (Long) params.getParValue("aviStoreEveryXCycles");
double timeBetweenScreenshots = params.getParValueDouble("framesPerSecond");
BufferedImage gesamtBild;
BufferedImage alles = new BufferedImage(
this.aviDimWidth,
this.aviDimHeight,
BufferedImage.TYPE_INT_RGB);
String pfad = params.getStdDirectory() + File.separator;
String datei =
pfad
+ datNam
+ StaticMethods.normZahl(this.filmNumAVI, 6)
+ ".avi";
double bilderProSek = timeBetweenScreenshots / bildIntAVI;
// String[] infos;
// infos = new String[1];
// infos[0] = "Tick: " + simZyk;
// infos[1] = "Koll %: " + GlobaleVariablen.getCollCount();
// infos[2] = "GP %: " + GlobaleVariablen.getGateCount();
try {
if (this.AVIout == null) {
this.AVIout = new AVIOutputStream(new File(datei),
AVIOutputStream.VideoFormat.PNG);
this.AVIout.setVideoCompressionQuality(1f);
this.AVIout.setTimeScale(1);
this.AVIout.setFrameRate((int) Math.round(bilderProSek));
StaticMethods.log(
StaticMethods.LOG_INFO,
"AVI-Datei-Strom erzeugt: " + datei,
params);
}
gesamtBild = this.erzeugeBild(umg, params);
Graphics2D g = alles.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, alles.getWidth(), alles.getHeight());
g.drawImage(gesamtBild, 0, 0, null);
this.AVIout.writeFrame(alles);
} catch (final Exception e) {
throw new RuntimeException("AVI-Frame nicht gespeichert: " + e);
}
}
/**
* Speichert die Bilderfolge der Simulation als GIF-Datei.
*
* @param datNam Der Dateiname.
* @param params Der Parametersatz.
*/
private void gifSpeichern(
final String datNam,
final ParCollection params) {
if (datNam == null || datNam.equals("null")) {
return;
}
double timeBetweenScreenshots = params.getParValueDouble("framesPerSecond");
long bildIntGIF = (Long) params.getParValue("gifStoreEveryXCycles");
String pfad = params.getStdDirectory() + File.separator;
String datei =
pfad
+ datNam
+ StaticMethods.normZahl(this.filmNumGIF, 6)
+ ".gif";
FileOutputStream fs;
Image[] imgs = new Image[this.bilder.size()];
int i = 0;
double bilderProSek = timeBetweenScreenshots / bildIntGIF;
for (Image img : this.bilder) {
imgs[i] = img;
i++;
}
try {
fs = new FileOutputStream(datei);
SimpleGIF.writeAnimatedGIF(
imgs,
"",
false,
bilderProSek,
fs);
} catch (final Exception e) {
throw new RuntimeException("GIF nicht gespeichert: " + e);
}
this.filmNumGIF++;
StaticMethods.log(
StaticMethods.LOG_INFO,
"GIF-Datei gespeichert: " + datei,
params);
}
/**
* Speichert die Bilderfolge der Simulation als AVI-Datei.
*
* @param params Der Parametersatz.
*/
private void aviSpeichern(final ParCollection params) {
String aviDatNam = this.avifile;
if (aviDatNam == null || aviDatNam.equals("null")) {
aviDatNam = null;
}
String pfad = params.getStdDirectory();
String datNam;
String datei;
if (aviDatNam != null) {
datNam = aviDatNam;
} else {
return;
}
if (this.AVIout != null) {
try {
this.AVIout.close();
} catch(final Exception e) {
throw new RuntimeException("AVI nicht gespeichert: " + e);
}
}
this.AVIout = null;
datei = pfad
+ File.separator
+ datNam
+ StaticMethods.normZahl(this.filmNumAVI, 6)
+ ".avi";
this.filmNumAVI++;
StaticMethods.log(
StaticMethods.LOG_INFO,
"AVI-Datei gespeichert: "
+ datei
+ "(Größe: "
+ new File(datei).length()
+ " Bytes).",
params);
}
private String avifile;
private String giffile;
private boolean firstTimeFollow = true;
private double currentFollowerSpeed;
private final double maxSpeed = Double.POSITIVE_INFINITY;
private double lastDistance = Double.POSITIVE_INFINITY;
// private Double acceleration = null;
@SuppressWarnings({ "rawtypes" })
private void followMarkedAgent(AbstractEnvironment<AbstractAgent<?>> umg) {
// AbstractEnvironment2D<AbstractAgent2D> env2D = null;
try {
env2D = (AbstractEnvironment2D) umg;
} catch (Exception e) {
return;
}
try {
if (this.follow && this.markedAgentId != null) {
// if (this.acceleration == null) {
// this.acceleration = umg.getPars().getParValueDouble(AllroundVideoPlugin.TRANSLATION_ACC_PAR_NAME);
// }
// env2D.setZoomBoxMiddle(env2D.getAgentPosition(this.markedAgentId));
Vector2D agentPos = new Vector2D(env2D.getAgentPosition(this.markedAgentId));
Vector2D zoomBoxPos = new Vector2D(env2D.getZoomBoxMiddle());
double distance = zoomBoxPos.distance(agentPos);
if (this.currentFollowerSpeed < this.maxSpeed) {
this.currentFollowerSpeed += cameraTranslationAcceleration;
}
if (lastDistance / distance < 0.1) {
this.currentFollowerSpeed = 0;
}
double speed = Math.min(distance, this.currentFollowerSpeed);
Vector2D dir = new Vector2D(agentPos).sub(zoomBoxPos);
Vector2D newPos = zoomBoxPos.add(dir.setLength(speed));
this.lastDistance = distance;
env2D.setZoomBoxMiddle(newPos);
this.rotationCenter = env2D.getZoomBoxMiddle(); // env2D.getAgentPosition(this.markedAgentId);
this.rotationAngle = -env2D.getAgentAngle(this.markedAgentId) * Math.PI / 180 + Math.PI;
} else if (this.manualCenterPt == null) {
env2D.resetVisualizationAngle();
this.firstTimeFollow = true;
rotationCenter = null;
rotationAngle = 0;
}
} catch (Exception e) {
}
}
private Vector2D rotationCenter;
private double rotationAngle;
// private Double rotationSpeed = null;
private AbstractEnvironment2D<?> env2D;
private void setAngleSmooth() {
if (rotationCenter != null) {
// if (rotationSpeed == null) {
// this.cameraRotationSpeedForFollowingAgent = params.getParValueDouble("CameraRotationSpeedForFollowingAgent");
// }
double step = cameraRotationSpeedForFollowingAgent;
double angle = env2D.getVisualizationAngleRAD();
double gultAngle = this.gultWinkel(angle);
rotationAngle = this.gultWinkel(rotationAngle);
if (Math.abs(gultAngle - rotationAngle) <= step) {
env2D.setVisualizationAngle(rotationCenter, rotationAngle);
} else {
if (rotationAngle - gultAngle > 0 && rotationAngle - gultAngle < Math.PI) {
env2D.setVisualizationAngle(rotationCenter, angle + step);
} else {
env2D.setVisualizationAngle(rotationCenter, angle - step);
}
}
if (this.firstTimeFollow) {
this.setZoom2DPlus();
this.setZoom2DMinus();
this.firstTimeFollow = false;
}
}
}
/**
* Erzeugt einen gültigen Winkel zwischen 0 (=) und 2 * Math.PI (<).
*
* @param w Der zu normalisierende Winkel.
*
* @return Der normalisierte Winkel.
*/
private double gultWinkel(final double w) {
double w2 = w;
while (w2 >= Math.PI * 2) { // Modulo??
w2 = w2 - Math.PI * 2;
}
while (w2 < 0) {
w2 = w2 + Math.PI * 2;
}
return w2;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void adjustZoomBoxMiddle(Vector2D deltaVector) {
AbstractEnvironment2D<AbstractAgent2D> env2D = null;
try {
env2D = (AbstractEnvironment2D) this.environment;
if (env2D.getZoomBox() == null) {
Rectangle2D boundingBox = env2D.getBoundingBox(false);
env2D.setZoomBox(new Rectangle2D(boundingBox.upperLeftCorner(), boundingBox.lowerRightCorner()));
}
Vector2D delta = new Vector2D(deltaVector);
double globalScale = env2D.globalScale();
delta.scale(Vector2D.NULL_VECTOR, new Vector2D(1 / globalScale, 1 / globalScale));
Vector2D newMiddle = new Vector2D(env2D.getZoomBoxMiddle());
newMiddle.translate(delta);
env2D.setZoomBoxMiddle(newMiddle);
} catch (Exception e) {
}
}
private long lastTime;
/**
* @param pauseIntervalMs Pause interval between ticks.
*/
public void setPauseInterval(int pauseIntervalMs) {
if (this.liveWindow != null) {
this.liveWindow.setPauseInterval(pauseIntervalMs);
}
}
/**
* Initiiert die Speicherung von Einzelbildern und der Gesamtfilme.
*/
@Override
public synchronized void runDuringSimulation(
AbstractEnvironment<AbstractAgent<?>> umg,
Wink simZyk,
ParCollection params) {
while (this.liveFilm && this.liveWindow == null) {
try {Thread.sleep(50);} catch (Exception e) {}
}
if (this.liveFilm) {
double num = liveWindow.pauseInterval / 50 + 1;
if (simZyk.isTick()) {
for (double i = 1; i < num; i++) {
umg.getSimTime().requestNotification(this, simZyk.getCurrentTime() + i * 1 / num);
}
}
/*
* Little pause between ticks.
*/
if (liveWindow.pauseInterval != 0) {
long timeElapsed = System.currentTimeMillis() - lastTime;
try {
Thread.sleep((long) (Math.max(0, liveWindow.pauseInterval / num - timeElapsed)));
} catch (InterruptedException e) {
}
this.lastTime = System.currentTimeMillis();
}
}
/*
* Global pause.
*/
while (this.pause) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
if (this.liveWindow != null) {
this.liveWindow.showTooltipp(null);
}
// Follow marked Agent:
this.followMarkedAgent(umg);
this.setAngleSmooth();
// String[] infos;
// infos = new String[1];
// infos[0] = "Ticks: " + simZyk;
// infos[1] = "Koll %: " + GlobaleVariablen.getCollCount();
// infos[2] = "GP %: " + GlobaleVariablen.getGateCount();
boolean isActive = false;
avifile = (String) params.getParValue("avifile");
giffile = (String) params.getParValue(GIF_DATEI_PAR);
long zwSpAVI = (Long) params.getParValue("aviImagesPerFile");
long zwSpGIF = (Long) params.getParValue("gifImagesPerFile");
long bildIntAVI = (Long) params.getParValue("aviStoreEveryXCycles");
long bildIntGIF = (Long) params.getParValue("gifStoreEveryXCycles");
if (avifile.equals("null")) {
avifile = null;
} else {
avifile = umg.getEnvironmentName() + "_" + avifile;
}
if (giffile.equals("null")) {
giffile = null;
} else {
giffile = umg.getEnvironmentName() + "_" + giffile;
}
if (this.neglectTicks && avifile == null && giffile == null) {
umg.getSimTime().neglectTicks(this);
}
if (avifile != null) {
isActive = true;
if (simZyk.isTick() && simZyk.getLastTick() % bildIntAVI == 0) {
this.aviFrameHinzufuegen(avifile, umg, params);
}
if (simZyk.isTick() && simZyk.getLastTick() != 0
&& simZyk.getLastTick() % zwSpAVI == 0 ) {
this.aviSpeichern(params);
}
}
if (giffile != null) {
isActive = true;
if (simZyk.isTick() && simZyk.getLastTick() % bildIntGIF == 0) {
this.bilder.add(this.erzeugeBild(umg, params));
}
if (simZyk.isTick() && simZyk.getLastTick() != 0
&& simZyk.getLastTick() % zwSpGIF == 0 ) {
this.gifSpeichern(giffile, params);
this.bilder.clear();
}
}
if (this.liveFilm // && simZyk.isTick()
&& simZyk.getLastTick() % this.liveCyc == 0
&& this.liveWindow != null && this.liveWindow.isVisible()) {
isActive = true;
BufferedImage gesamtBild = this.erzeugeBild(umg, params);
if (this.liveWindow != null) {
if (simZyk.getLastTick() == 0) {
// this.liveWindow.setSize(
// 20 + gesamtBild.getWidth(),
// 20 + gesamtBild.getHeight()
// + this.liveWindow.getInsets().top);
// this.liveWindow.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
if (this.currentEnv2D != null) {
if (this.markedAgentId == null) {
this.currentEnv2D.setScreenWidth(liveWindow.getWidth() - 0);
} else {
int width = 200;
if (this.autImgStored != null) {
width = this.autImgStored.getWidth();
}
this.currentEnv2D.setScreenWidth(liveWindow.getWidth() - width);
}
this.currentEnv2D.setScreenHeight(liveWindow.getHeight() - 20);
}
this.liveWindow.metaInfVis.img = gesamtBild;
this.liveWindow.repaint();
}
}
if (isActive) {
umg.addVisualizer(this);
} else {
umg.removeVisualizer(this);
}
}
/**
* Speicherung der Gesamtfilme nach der Simulation.
*/
@Override
public void runAfterSimulation(AbstractEnvironment<AbstractAgent<?>> umg, ParCollection params) {
this.aviSpeichern(params);
this.gifSpeichern(giffile, params);
this.terminated = true;
if (this.liveWindow != null) {
this.liveWindow.repaint();
}
if (params.getParValueBoolean("closeWindowsFramesOnTermination") && this.liveFilm) {
if (this.liveWindow != null) {
this.liveWindow.disposeAll();
}
}
}
private boolean terminated = false;
private AbstractEnvironment<AbstractAgent<?>> environment;
public AbstractEnvironment<AbstractAgent<?>> getEnvironment() {
return this.environment;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void runBeforeSimulation(
final AbstractEnvironment<AbstractAgent<?>> umg,
final ParCollection params) {
this.environment = umg;
this.aviDimWidth = params.getParValueInt("aviwidth");
this.aviDimHeight = params.getParValueInt("aviheight");
umg.addVisualizer(this);
this.currentEnv = umg;
try {
this.currentEnv2D = (AbstractEnvironment2D) this.currentEnv;
} catch (Exception e) {
}
this.liveFilm = params.getParValueBoolean(AllroundVideoPlugin.LIVE_FILM_PAR);
this.liveCyc = 1;
if (this.liveFilm) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
AllroundVideoPlugin.this.liveWindow = new LiveWindow(
"Live Simulation View",
umg,
AllroundVideoPlugin.this,
params,
true);
}
});
}
// /*
// * Wait a little while to assure that video frame has opened
// * befor simulation start.
// */
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
private boolean neglectTicks = false;
@SuppressWarnings({ "unchecked", "rawtypes" })
public void setFitPerfectly(final boolean isPerfect) {
AbstractEnvironment2D<AbstractAgent2D> env2D = null;
try {
env2D = (AbstractEnvironment2D) this.environment;
env2D.setPerfectFit(isPerfect);
} catch (Exception e) {
return;
}
}
/**
* Sets the zoom box of the environment to the specified rectangle - only
* if the environment is assignable to AbstractEnvironment2D.
*
* @param area The rectangle to set the zoom box to.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public void setZoom(final Rectangle2D area) {
AbstractEnvironment2D<AbstractAgent2D> env2D = null;
try {
env2D = (AbstractEnvironment2D) this.environment;
} catch (Exception e) {
return;
}
if (area == null) {
env2D.setZoomBox(null);
} else {
env2D.setZoomBox(new Rectangle2D(
env2D.getRealPosFromScreenPos(area.upperLeftCorner()),
env2D.getRealPosFromScreenPos(area.lowerRightCorner())));
}
}
/**
* @return Returns the neglectTicks.
*/
public boolean isNeglectTicks() {
return this.neglectTicks;
}
/**
* @param neglectTicks The neglectTicks to set.
*/
public void setNeglectTicks(boolean neglectTicks) {
this.neglectTicks = neglectTicks;
}
/**
* Über diese Methode können Abhängigkeiten zwischen Plugins definiert
* werden. Die hier zurückgegebene Liste sollte die IDs aller Plugins
* enthalten, die von diesem Plugin benötigt werden und ohne die kein
* Start der Simulation möglich sein soll.
*
* @return Die Liste benötigter Plugins. Diese Liste kann <code>null</code>
* sein, wenn keine abhängigkeiten definiert werden sollen.
*/
@Override
public List<String> getRequiredPlugins() {
return null;
}
/**
* The environment.
*/
private AbstractEnvironment<AbstractAgent<?>> currentEnv;
/**
* @return Returns the currentEnv.
*/
public AbstractEnvironment<AbstractAgent<?>> getCurrentEnv() {
return this.currentEnv;
}
/**
* The environment if it is of type AbstractEnvironment2D, null otherwise.
*/
private AbstractEnvironment2D<AbstractAgent2D<?>> currentEnv2D;
/**
* The id of the currently marked agent.
*/
private Integer markedAgentId = null;
/**
* The click position on the visualization canvas.
*/
public void setClickPosition(final int x, final int y) {
Integer oldMarkedAgentID = this.markedAgentId;
Vector2D clickPos = new Vector2D(x, y);
Vector2D agentPos;
List<AbstractAgent<?>> agents = this.currentEnv.getAgents();
double min = Double.MAX_VALUE;
double akt;
Integer markedID = null;
AbstractAgent<?> agent2D = null;
try {
@SuppressWarnings("rawtypes")
AbstractEnvironment2D env2D = (AbstractEnvironment2D) this.currentEnv;
agent2D = env2D.getAgentAtPosition(env2D.getRealPosFromScreenPos(new Vector2D(x, y)));
} catch (Exception e) {
}
if (agent2D != null) {
this.markedAgentId = agent2D.id();
} else {
for (AbstractAgent<?> a : agents) {
agentPos = this.currentEnv.getPositionInVisualization(a.id());
akt = agentPos.distance(clickPos);
if (min > akt) {
markedID = a.id();
min = akt;
}
}
this.markedAgentId = markedID;
}
if (oldMarkedAgentID == null && this.markedAgentId != null && this.follow) {
// this.setZoom2DPlus();
// this.setZoom2DPlus();
// this.setZoom2DPlus();
}
}
public void setMarkedAgentId(Integer markedAgentId) {
this.markedAgentId = markedAgentId;
}
public void unmarkSelektion() {
this.markedAgentId = null;
// this.setZoom2DMinus();
// this.setZoom2DMinus();
// this.setZoom2DMinus();
}
public void requestTicks() {
this.environment.getSimTime().requestTicks(this);
this.environment.addVisualizer(this);
}
public void neglectTicks() {
this.environment.getSimTime().neglectTicks(this);
this.environment.removeVisualizer(this);
}
public boolean isSimulationTerminated() {
return this.terminated;
}
@Override
public void handleEvent(
final EASEvent e,
final AbstractEnvironment<AbstractAgent<?>> env,
final Wink lastTick,
final ParCollection params) {
if (this.giffile == null && this.avifile == null) {
this.runDuringSimulation(env, lastTick, params);
}
}
private boolean follow = false;
/**
* @return Returns the follow.
*/
public boolean isFollow() {
return this.follow;
}
public void setFollowAgent(final boolean followMarkedAgent) {
this.follow = followMarkedAgent;
}
public void setZoom2DPlus() {
try {
@SuppressWarnings("rawtypes")
AbstractEnvironment2D env = (AbstractEnvironment2D) this.environment;
double scale = 1 / 1.2;
env.setZoomScale(scale);
} catch (Exception e) {
}
}
public void setZoom2DMinus() {
try {
@SuppressWarnings("rawtypes")
AbstractEnvironment2D env = (AbstractEnvironment2D) this.environment;
double scale = 1.2;
env.setZoomScale(scale);
} catch (Exception e) {
}
}
public double getScale() {
try {
@SuppressWarnings("rawtypes")
AbstractEnvironment2D env = (AbstractEnvironment2D) this.environment;
return env.globalScale();
} catch (Exception e) {
return 1;
}
}
private boolean pause = false;
public void pause() {
// this.environment.getSimTime().setGlobalPause(true);
this.pause = true;
}
public void depause() {
this.pause = false;
if (this.liveWindow != null) {
this.liveWindow.requestFocus();
}
// this.environment.getSimTime().setGlobalPause(false);
}
public boolean getPause() {
return this.pause;
}
public List<GridObject> getGridObjectsUnderMouse(final int x, final int y) {
// if (!this.liveWindow.hasFocus()) {
// return null;
// }
try {
AbstractGridEnvironment<?> gridEnv = (AbstractGridEnvironment<?>) this.environment;
final Vector2D pos = gridEnv.getRealPosFromScreenPos(new Vector2D(x, y));
LinkedList<GridObject> goList = new LinkedList<GridObject>();
goList.add(new GridObject() {
/**
*
*/
private static final long serialVersionUID = 6936866534584412400L;
@Override public BufferedImage getOutsideView() {return null;}
@Override public BufferedImage getInsideView() {return null;}
@Override public Polygon2D getAgentShape() {return null;}
@Override public Color getAgentColor() {return null;}
@Override public String toString() {return "Grid cell <" + (int) (Math.round(pos.x)) + " / " + (int) (Math.round(pos.y)) + ">";}
});
goList.addAll(gridEnv.getRealFieldPosition((int) Math.round(pos.x), (int) Math.round(pos.y)));
return goList;
} catch (Exception e) {
return null;
}
}
@Override
public List<String> getSupportedPlugins() {
return null;
}
private Vector2D manualCenterPt = null;
public void setVisualizationAngle(Vector2D centerPoint, double angleRAD) {
try {
this.manualCenterPt = centerPoint;
this.env2D.setVisualizationAngle(centerPoint, angleRAD);
this.env2D.requestRedraw();
} catch (Exception e) {}
}
public void showTooltipps(boolean show) {
this.liveWindow.setShowTooltipp(show);
}
public AbstractEnvironment2D<?> getEnv2D() {
return this.env2D;
}
@Override
public void onSimulationResumed(AbstractEnvironment<AbstractAgent<?>> env,
Wink resumeTime, ParCollection params) {
super.onSimulationResumed(env, resumeTime, params);
if (this.liveFilm) {
this.liveWindow.setVisible(true);
this.liveWindow.controlPanel.setVisible(true);
this.liveWindow.metaInfVis.setVisible(true);
// if (this.env2D != null) {
// this.env2D.requestRedraw();
// }
}
}
}