/*
* Copyright 2004-2010 Information & Software Engineering Group (188/1)
* Institute of Software Technology and Interactive Systems
* Vienna University of Technology, Austria
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.tuwien.ifs.somtoolbox.output;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import com.martiansoftware.jsap.JSAPResult;
import com.martiansoftware.jsap.Parameter;
import at.tuwien.ifs.somtoolbox.apps.SOMToolboxApp;
import at.tuwien.ifs.somtoolbox.apps.config.AbstractOptionFactory;
import at.tuwien.ifs.somtoolbox.apps.config.OptionFactory;
import at.tuwien.ifs.somtoolbox.input.SOMLibFormatInputReader;
import at.tuwien.ifs.somtoolbox.layers.LayerAccessException;
import at.tuwien.ifs.somtoolbox.layers.Unit;
import at.tuwien.ifs.somtoolbox.models.GrowingSOM;
/**
* Generates a graphical representation of a trajectory of the given points over the map.
*
* @author Michael Dittenbach
* @version $Id: TrajectoryOutputter.java 3688 2010-07-15 09:17:46Z frank $
*/
public class TrajectoryOutputter implements SOMToolboxApp {
public static final Parameter[] OPTIONS = new Parameter[] { OptionFactory.getOptHighlightedDataNamesFile(true),
OptionFactory.getOptUnitDescriptionFile(true), OptionFactory.getOptMapDescriptionFile(false),
OptionFactory.getSwitchDrawLines(), OptionFactory.getOptImageFileName() };
public static final String DESCRIPTION = "Generates a graphical representation of a trajectory of the given points over the map";
public static final String LONG_DESCRIPTION = DESCRIPTION;
public static final Type APPLICATION_TYPE = Type.Utils;
private static final int unitWidth = 100;
private static final int unitHeight = 130;
public static void main(String[] args) {
// -d dataNamesFilename, mand.
// -u unitDescriptionFileName, mand.
// -m mapDescriptionFileName, opt.
// -l drawLines, switch
// imageName
// register and parse all options
JSAPResult config = AbstractOptionFactory.parseResults(args, OPTIONS);
String dataNamesFileName = config.getString("dataNamesFile");
String unitDescriptionFileName = config.getString("unitDescriptionFile");
String mapDescriptionFileName = config.getString("mapDescriptionFile", null);
String imageFileName = config.getString("imageFile");
boolean drawLines = config.getBoolean("drawLines");
String fDir = imageFileName.substring(0, imageFileName.lastIndexOf(System.getProperty("file.separator")) + 1);
String fName = imageFileName.substring(imageFileName.lastIndexOf(System.getProperty("file.separator")) + 1);
if (fName.endsWith(".png") || fName.endsWith(".eps")) {
fName = fName.substring(0, (fName.length() - 4));
}
GrowingSOM gsom = null;
try {
gsom = new GrowingSOM(new SOMLibFormatInputReader(null, unitDescriptionFileName, mapDescriptionFileName));
} catch (Exception e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(e.getMessage() + " Aborting.");
System.exit(-1);
}
String[] dataNames = readDataNames(dataNamesFileName);
/*
* animation code for (int i=0; i<dataNames.length;i++) { String[] dnAni = new String[i+1]; for (int j=0;j<(i+1);j++) { dnAni[j] =
* dataNames[j]; } try { write(gsom, fDir, fName+""+i, dnAni, drawLines); } catch (IOException e) {
* Logger.getLogger("at.tuwien.ifs.somtoolbox").severe("asf"); // TODO: change string System.exit(-1); } }
*/
try {
write(gsom, fDir, fName, dataNames, drawLines);
} catch (IOException e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe("IOExeption while writing: " + e.getMessage()); // TODO:
// change
// string
System.exit(-1);
}
}
/*
* public static void write(GHSOM ghsom, String fDir, String fName, String[] dataNames) throws IOException { write(ghsom.topLayerMap(), fDir,
* fName, dataNames); }
*/
public static void write(GrowingSOM gsom, String fDir, String fName, String[] dataNames, boolean drawLines)
throws IOException {
int imageWidth = gsom.getLayer().getXSize() * unitWidth + 5;
int imageHeight = gsom.getLayer().getYSize() * unitHeight + 5;
/** ** png output *** */
BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics();
createGraphics(g, imageWidth, imageHeight, gsom, dataNames, drawLines);
ImageIO.write(image, "png", new File(fDir + fName + ".png"));
/** ** eps output *** */
try {
@SuppressWarnings("unchecked")
Class<Graphics2D> c = (Class<Graphics2D>) Class.forName("org.sourceforge.jlibeps.epsgraphics.EpsGraphics2D");
Constructor<Graphics2D> constr = c.getConstructor(String.class, OutputStream.class, int.class, int.class,
int.class, int.class);
FileOutputStream epsOut = new FileOutputStream(fDir + fName + ".eps");
// EpsGraphics2D geps = new EpsGraphics2D(fName, epsOut, 0, 0, imageWidth, imageHeight);
Graphics2D geps = constr.newInstance(new Object[] { fName, epsOut, 0, 0, imageWidth, imageHeight });
createGraphics(geps, imageWidth, imageHeight, gsom, dataNames, drawLines);
// geps.flush();
c.getMethod("flush", new Class<?>[] {}).invoke(geps, new Object[] {});
// geps.close();
c.getMethod("close", new Class<?>[] {}).invoke(geps, new Object[] {});
} catch (Exception e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"EPS-Output not possible. To enable add \"jlibeps.jar\" to your classpath");
}
}
private static int[][] getNrDataNames(GrowingSOM gsom, String[] dataNames) {
int[][] res = new int[gsom.getLayer().getXSize()][gsom.getLayer().getYSize()];
try {
for (int j = 0; j < gsom.getLayer().getYSize(); j++) {
for (int i = 0; i < gsom.getLayer().getXSize(); i++) {
res[i][j] = 0;
for (String dataName : dataNames) {
for (int mi = 0; mi < gsom.getLayer().getUnit(i, j).getNumberOfMappedInputs(); mi++) {
if (dataName.equals(gsom.getLayer().getUnit(i, j).getMappedInputNames()[mi])) {
res[i][j]++;
}
}
}
}
}
} catch (LayerAccessException e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(e.getMessage());
System.exit(-1);
}
return res;
}
private static int getMaxNrDataNames(int[][] nrDataNames, int x, int y) {
int res = 0;
for (int j = 0; j < y; j++) {
for (int i = 0; i < x; i++) {
if (nrDataNames[i][j] > res) {
res = nrDataNames[i][j];
}
}
}
return res;
}
private static void createGraphics(Graphics2D g, int imageWidth, int imageHeight, GrowingSOM gsom,
String[] dataNames, boolean drawLines) {
g.setColor(Color.white);
g.fillRect(0, 0, imageWidth, imageHeight);
g.setColor(Color.black);
// frame
g.setStroke(new BasicStroke(4));
g.draw(new Rectangle2D.Double(1, 1, imageWidth - 2, imageHeight - 2));
int[][] nrDataNames = getNrDataNames(gsom, dataNames);
int maxDataNames = getMaxNrDataNames(nrDataNames, gsom.getLayer().getXSize(), gsom.getLayer().getYSize());
for (int j = 0; j < gsom.getLayer().getYSize(); j++) {
for (int i = 0; i < gsom.getLayer().getXSize(); i++) {
Unit u = null;
try {
u = gsom.getLayer().getUnit(i, j);
} catch (LayerAccessException e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(e.getMessage());
System.exit(-1);
}
g.setStroke(new BasicStroke(1));
g.setColor(Color.lightGray);
int luCornerX = i * unitWidth + 1;
int luCornerY = j * unitHeight + 1;
/** ** unit rectangle begin *** */
if (nrDataNames[i][j] > 0) {
int minGreen = 133;
int maxGreen = 211;
int minBlue = 0;
int maxBlue = 163;
int green = 0;
int blue = 0;
if (maxDataNames == 1) {
green = minGreen;
blue = minBlue;
} else {
green = (maxGreen - minGreen) / (maxDataNames - 1) * (maxDataNames - nrDataNames[i][j])
+ minGreen;
blue = (maxBlue - minBlue) / (maxDataNames - 1) * (maxDataNames - nrDataNames[i][j]) + minBlue;
}
// System.out.println("Unit "+i+"/"+j+": 255,"+green+","+blue);
Color bg = new Color(255, green, blue);
g.setPaint(bg);
g.fill(new Rectangle2D.Double((i * unitWidth + 3), (j * unitHeight + 3), unitWidth - 1,
unitHeight - 1));
} else {
// g.setPaint(Color.white);
// System.out.println("x1:"+((i*unitWidth)+1)+", y1:"+((j*unitHeight)+1)+", x2:"+((i*unitWidth)+unitWidth)+",
// y2:"+((j*unitHeight)+unitHeight));
g.draw(new Rectangle2D.Double((i * unitWidth + 3), (j * unitHeight + 3), unitWidth - 1,
unitHeight - 1));
// System.out.println("Unit "+i+"/"+j+": no color");
}
/** ** unit rectangle end *** */
/** ** labels begin *** */
int textPaddingX = 3;
int textPaddingY = 2;
int fontSize = 8;
int textPosY = luCornerY + textPaddingY + fontSize;
if (u.getLabels() != null) {
g.setFont(new Font("Sans", Font.PLAIN, fontSize));
g.setColor(Color.black); // TODO: color according to qe?
for (int l = 0; l < u.getLabels().length; l++) {
g.drawString(u.getLabels()[l].getName(), (luCornerX + textPaddingX), textPosY);
textPosY += fontSize + textPaddingY;
}
}
/** ** labels end *** */
/** ** data *** */
boolean separator = true;
if (u.getNumberOfMappedInputs() > 0) {
g.setFont(new Font("Sans", Font.BOLD, fontSize));
g.setColor(Color.decode("#4c9b21")); // dark green
for (String dataName : dataNames) {
boolean found = false;
int mi = 0;
while (mi < u.getNumberOfMappedInputs() && !found) {
if (dataName.equals(u.getMappedInputNames()[mi])) {
found = true;
if (separator) {
Color oldCol = g.getColor();
g.setColor(Color.black);
g.draw(new Line2D.Double((luCornerX + textPaddingX), textPosY - 6, (luCornerX
+ textPaddingX + unitWidth - textPaddingX), textPosY - 6));
g.setColor(oldCol);
textPosY += 4;
separator = false;
}
g.drawString(dataName, (luCornerX + textPaddingX), textPosY);
textPosY += fontSize + 0; // textPaddingY;
}
mi++;
}
}
}
/** ** data *** */
}
}
int x = 0;
int y = 0;
if (drawLines == true) {
GeneralPath trajectory = new GeneralPath(Path2D.WIND_EVEN_ODD, dataNames.length);
for (int d = 0; d < dataNames.length; d++) {
Unit u = gsom.getLayer().getUnitForDatum(dataNames[d]);
if (u == null) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
"Datum " + dataNames[d] + " not found on map. Aborting.");
System.exit(-1); // TODO: exception or ignore
}
x = u.getXPos() * unitWidth + unitWidth / 2;
y = u.getYPos() * unitHeight + unitHeight / 2;
if (d == 0) {
trajectory.moveTo(x, y);
/* starting point begin */
g.setColor(Color.black);
g.setStroke(new BasicStroke(2));
g.draw(new Ellipse2D.Double(x - 5, y - 5, 10, 10));
/* starting point end */
} else {
trajectory.lineTo(x, y);
// int oldX = (gsom.getLayer().getUnitForDatum(dataNames[d - 1]).getXPos() * unitWidth) + (unitWidth
// / 2);
// int oldY = (gsom.getLayer().getUnitForDatum(dataNames[d - 1]).getYPos() * unitHeight) +
// (unitHeight / 2);
}
}
g.setColor(Color.red);
g.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g.draw(trajectory);
/* end point begin */
g.setColor(Color.black);
g.setStroke(new BasicStroke(2));
g.fill(new Ellipse2D.Double(x - 5, y - 5, 10, 10));
/* end point end */
}
}
public static String[] readDataNames(String fName) {
ArrayList<String> tmpList = new ArrayList<String>();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(fName));
String line = null;
while ((line = br.readLine()) != null) {
StringTokenizer strtok = new StringTokenizer(line, " \t", false);
while (strtok.hasMoreTokens()) {
tmpList.add(strtok.nextToken());
}
}
} catch (IOException e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
"Could not open or read from file " + fName + " containing the data names. Aborting.");
System.exit(-1);
}
if (tmpList.isEmpty()) {
return null;
} else {
String[] res = new String[tmpList.size()];
for (int i = 0; i < tmpList.size(); i++) {
res[i] = tmpList.get(i);
}
return res;
}
}
}