package ika.geoexport; import java.io.PrintWriter; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; /** * * @author jenny */ public final class OBJGridWriter { /** * if a vertex is not valid, this value is written instead */ private static final String NO_DATA_VALUE = "0"; /** * A system dependent separator string, typically '\n' or '\r' or a * combination of the two. */ private static final String NL = System.getProperty("line.separator"); private final PrintWriter writer; private final int cols; private final int rows; private final double cellSize; private final DecimalFormat vertexFormat; private final boolean writeTexture; /** * Counts the number of vertices written to the file. */ private int vertexCounter = 0; public OBJGridWriter(PrintWriter writer, int cols, int rows, double cellSize, boolean writeTexture) { if (cols <= 1 || rows <= 1 || cellSize <= 0) { throw new IllegalArgumentException(); } vertexFormat = new DecimalFormat("##0.######"); DecimalFormatSymbols dfs = vertexFormat.getDecimalFormatSymbols(); dfs.setDecimalSeparator('.'); vertexFormat.setDecimalFormatSymbols(dfs); this.writer = writer; this.cols = cols; this.rows = rows; this.cellSize = cellSize; this.writeTexture = writeTexture; } /** * Writes a value to the grid file. Throws an exception if all possible * values have already been written. * @param v The value to write to the file. Can be NaN or infinite. */ public void write(float v) { assertGridNotFull(); double x = vertexCounter % cols * cellSize; double y = (int) (vertexCounter / cols) * cellSize; writer.write("v "); writer.write(vertexFormat.format(x)); writer.write(" "); writer.write(vertexFormat.format(y)); writer.write(" "); if (Float.isNaN(v) || Float.isInfinite(v)) { writer.write(NO_DATA_VALUE); } else { writer.write(vertexFormat.format(v)); } writer.write(NL); ++vertexCounter; if (vertexCounter == cols * rows) { writeTrailer(); } } private void writeTrailer() { // write texture coordinates if (writeTexture) { for (int r = 0; r < rows; r++) { double y = (double) r / (rows - 1); for (int c = 0; c < cols; c++) { double x = (double) c / (cols - 1); writer.write("vt "); writer.write(vertexFormat.format(x)); writer.write(" "); writer.write(vertexFormat.format(y)); writer.write(NL); } } } // write faces for (int r = 1; r < rows; r++) { for (int c = 1; c < cols; c++) { // uper left triangle int id = c + (r - 1) * cols; // id of top left vertex writeTriangle(id, id + cols, id + 1); // lower right triangle writeTriangle(id + cols, id + cols + 1, id + 1); } } } private void writeTriangle(int ID1, int ID2, int ID3) { writer.write("f "); writer.write(vertexFormat.format(ID1)); if (writeTexture) { writer.write("/"); writer.write(vertexFormat.format(ID1)); } writer.write(" "); writer.write(vertexFormat.format(ID2)); if (writeTexture) { writer.write("/"); writer.write(vertexFormat.format(ID2)); } writer.write(" "); writer.write(vertexFormat.format(ID3)); if (writeTexture) { writer.write("/"); writer.write(vertexFormat.format(ID3)); } writer.write(NL); } /** * Make sure not all values have already been written to the grid file. */ private void assertGridNotFull() { if (vertexCounter >= cols * rows) { throw new IllegalStateException("grid is written completely"); } } }