Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008 package edu.tum.cs.vis.model.parser;
00009
00010 import java.awt.Color;
00011 import java.io.FileNotFoundException;
00012 import java.io.IOException;
00013 import java.io.RandomAccessFile;
00014 import java.nio.BufferOverflowException;
00015 import java.nio.BufferUnderflowException;
00016 import java.nio.ByteBuffer;
00017 import java.nio.ByteOrder;
00018 import java.util.ArrayList;
00019
00020 import edu.tum.cs.vis.model.Model;
00021 import edu.tum.cs.vis.model.util.Group;
00022 import edu.tum.cs.vis.model.util.Mesh;
00023 import edu.tum.cs.vis.model.util.Triangle;
00024 import edu.tum.cs.vis.model.util.Vertex;
00025
00032 public class PlyParser extends ModelParser {
00033
00040 private enum FileFormat {
00044 ASCII,
00048 LITTLE_ENDIAN,
00052 BIG_ENDIAN
00053 };
00054
00058 private ByteBuffer byteBuffer;
00059
00063 private FileFormat fileFormat;
00064
00071 private class Property {
00079 public Property(String name) {
00080 this.name = name;
00081 }
00082
00086 String type1 = null;
00090 String type2 = null;
00094 String name;
00095 }
00096
00103 private class ValueLine {
00107 ArrayList<Number> values = new ArrayList<Number>();
00108 }
00109
00116 private class Element {
00125 public Element(String n, int cnt) {
00126 this.name = n;
00127 this.cnt = cnt;
00128 }
00129
00133 String name;
00137 int cnt;
00141 ArrayList<Property> properties = new ArrayList<Property>();
00145 ArrayList<ValueLine> lines = new ArrayList<ValueLine>();
00146 };
00147
00151 private ArrayList<Element> elements = new ArrayList<Element>();
00152
00156 private int currentElement = 0;
00157
00161 @SuppressWarnings("unused")
00162 private void dump() {
00163 for (Element e : elements) {
00164 System.out.println(e.name);
00165 for (Property p : e.properties) {
00166 System.out.println("prop: " + p.name);
00167 System.out.println("prop: " + p.type1);
00168 System.out.println("prop: " + p.type2);
00169 }
00170 for (ValueLine l : e.lines) {
00171 for (Number n : l.values)
00172 System.out.print(n.toString() + " ");
00173 System.out.println("");
00174 }
00175 }
00176 }
00177
00178 @Override
00179 protected boolean loadModel(String filename) {
00180
00181 RandomAccessFile raf = null;
00182
00183 try {
00184 raf = new RandomAccessFile(filename, "r");
00185 boolean cont = false;
00186 String line = "";
00187 line = raf.readLine();
00188 if (line == null || line.compareTo("ply") != 0) {
00189 System.err.println("ERRROR: magic bytes 'ply' not found in file.");
00190 return false;
00191 }
00192 do {
00193 line = raf.readLine();
00194 if (line != null)
00195 cont = processLine(line.split(" "));
00196 } while (cont && line.compareTo("end_header") != 0);
00197
00198 if (cont) {
00199 if (fileFormat == FileFormat.ASCII) {
00200 do {
00201 line = raf.readLine();
00202 if (line != null)
00203 cont = processDataLine(line.split(" "));
00204 } while (cont && line != null);
00205 } else {
00206 int remain = (int) (raf.length() - raf.getFilePointer());
00207 byteBuffer = ByteBuffer.allocate(remain);
00208 if (fileFormat == FileFormat.BIG_ENDIAN)
00209 byteBuffer.order(ByteOrder.BIG_ENDIAN);
00210 else
00211 byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
00212
00213 for (int i = 0; i < remain; i++) {
00214 byte b = raf.readByte();
00215 byteBuffer.put(b);
00216 }
00217 byteBuffer.position(0);
00218 try {
00219 processDataBuffer();
00220
00221 } catch (BufferUnderflowException e) {
00222 System.err.println("Couldn't parse model. " + e.toString() + " "
00223 + e.getMessage());
00224 return false;
00225 } catch (BufferOverflowException e) {
00226 System.err.println("Couldn't parse model. " + e.toString() + " "
00227 + e.getMessage());
00228 return false;
00229 }
00230
00231 }
00232 }
00233 } catch (FileNotFoundException e) {
00234 System.out.println("ERROR: File not found: " + filename);
00235 return false;
00236 } catch (IOException e) {
00237 System.out.println("ERROR reading file: " + e.getMessage());
00238 } finally {
00239 try {
00240 if (raf != null)
00241 raf.close();
00242 } catch (IOException e) {
00243 System.out.println("ERROR closing file: " + e.getMessage());
00244 }
00245 }
00246
00247
00248
00249 try {
00250
00251 byteBuffer = null;
00252
00253 Element vertexElement = null;
00254 Element faceElement = null;
00255 for (Element e : elements) {
00256 if (e.name.compareTo("vertex") == 0) {
00257 vertexElement = e;
00258 }
00259 if (e.name.compareTo("face") == 0) {
00260 faceElement = e;
00261 }
00262 if (vertexElement != null && faceElement != null)
00263 break;
00264 }
00265
00266 if (vertexElement == null) {
00267 System.err.println("ERROR: .ply file doesn't contain vertex definition.");
00268 return false;
00269 }
00270
00271 if (faceElement == null) {
00272 System.err.println("ERROR: .ply file doesn't contain face definition.");
00273 return false;
00274 }
00275
00276 model = new Model();
00277 Group g = new Group(model);
00278 model.setGroup(g);
00279 Mesh m = new Mesh();
00280 g.setMesh(m);
00281
00282 model.setTextureBasePath(null);
00283
00284 int coordIdx[] = new int[] { -1, -1, -1 };
00285 int colorIdx[] = new int[] { -1, -1, -1 };
00286 int idxOk = 0;
00287 int colorOk = 0;
00288 for (int i = 0; i < vertexElement.properties.size(); i++) {
00289 Property p = vertexElement.properties.get(i);
00290 if (p.name.equals("x")) {
00291 coordIdx[0] = i;
00292 idxOk++;
00293 } else if (p.name.equals("y")) {
00294 coordIdx[1] = i;
00295 idxOk++;
00296 } else if (p.name.equals("z")) {
00297 coordIdx[2] = i;
00298 idxOk++;
00299 } else if (p.name.equals("red")) {
00300 colorIdx[0] = i;
00301 colorOk++;
00302 } else if (p.name.equals("green")) {
00303 colorIdx[1] = i;
00304 colorOk++;
00305 } else if (p.name.equals("nlue")) {
00306 colorIdx[2] = i;
00307 colorOk++;
00308 }
00309 }
00310
00311 if (idxOk != 3) {
00312 System.err.println("ERROR: x,y,z not properly defined for vertices in header.");
00313 model = null;
00314 return false;
00315 }
00316
00317 for (ValueLine l : vertexElement.lines) {
00318 if (l.values.size() < 3) {
00319 System.err.println("ERROR: invalid vertex coordinate count: " + l.values.size()
00320 + " for vertex index " + model.getVertices().size());
00321 model = null;
00322 return false;
00323 }
00324 Vertex v = new Vertex(l.values.get(coordIdx[0]).floatValue(), l.values.get(
00325 coordIdx[1]).floatValue(), l.values.get(coordIdx[2]).floatValue());
00326 if (colorOk == 3) {
00327 v.color = new Color(l.values.get(colorIdx[0]).intValue(), l.values.get(
00328 colorIdx[1]).intValue(), l.values.get(colorIdx[2]).intValue());
00329 }
00330 model.getVertices().add(v);
00331 }
00332
00333 for (ValueLine l : faceElement.lines) {
00334 if (l.values.size() < 3) {
00335 System.err.println("WARN: Skipping face with less than 3 points");
00336 } else if (l.values.size() == 3) {
00337 Triangle t = new Triangle();
00338 Vertex[] vert = new Vertex[3];
00339 for (int i = 0; i < 3; i++) {
00340 vert[i] = model.getVertices().get(l.values.get(i).intValue());
00341 }
00342 t.setPosition(vert);
00343 if (!t.calculateNormalVector()) {
00344 continue;
00345 }
00346 g.addTriangle(t);
00347 } else {
00348
00349 Vertex[] polyVert = new Vertex[l.values.size()];
00350 for (int i = 0; i < l.values.size(); i++) {
00351 polyVert[i] = model.getVertices().get(l.values.get(i).intValue());
00352 }
00353 int triangleIndices[] = polygonTriangulation(polyVert);
00354 for (int i = 0; i < triangleIndices.length / 3; i++) {
00355 Triangle t = new Triangle();
00356 Vertex[] vert = new Vertex[3];
00357 for (int j = 0; j < 3; j++) {
00358 vert[j] = polyVert[triangleIndices[i * 3 + j]];
00359 }
00360 t.setPosition(vert);
00361 if (!t.calculateNormalVector()) {
00362 continue;
00363 }
00364 g.addTriangle(t);
00365 }
00366 }
00367 }
00368 } catch (IndexOutOfBoundsException e) {
00369 System.err.println("Couldn't parse model. " + e.toString() + " " + e.getMessage());
00370 return false;
00371 } catch (BufferUnderflowException e) {
00372 System.err.println("Couldn't parse model. " + e.toString() + " " + e.getMessage());
00373 return false;
00374 } catch (BufferOverflowException e) {
00375 System.err.println("Couldn't parse model. " + e.toString() + " " + e.getMessage());
00376 return false;
00377 }
00378
00379 elements = null;
00380
00381 return true;
00382 }
00383
00392 private boolean processLine(String parts[]) {
00393 if (parts.length < 2)
00394 return true;
00395 if (parts[0].compareTo("format") == 0) {
00396 if (parts[1].compareTo("ascii") == 0)
00397 fileFormat = FileFormat.ASCII;
00398 else if (parts[1].compareTo("binary_little_endian") == 0)
00399 fileFormat = FileFormat.LITTLE_ENDIAN;
00400 else if (parts[1].compareTo("binary_big_endian") == 0)
00401 fileFormat = FileFormat.BIG_ENDIAN;
00402 else {
00403 System.err.println("ERROR: " + parts[0] + " header unknown: " + parts[1]);
00404 return false;
00405 }
00406 return true;
00407 } else if (parts[0].compareTo("element") == 0) {
00408 elements.add(new Element(parts[1], Integer.valueOf(parts[2])));
00409 return true;
00410 } else if (parts[0].compareTo("property") == 0) {
00411 Property p = new Property(parts[parts.length - 1]);
00412 if (parts[1].compareTo("list") == 0) {
00413 p.type1 = parts[2];
00414 p.type2 = parts[3];
00415 } else {
00416 p.type1 = parts[1];
00417 }
00418 elements.get(elements.size() - 1).properties.add(p);
00419 return true;
00420 }
00421 return true;
00422 }
00423
00431 private boolean processDataLine(String parts[]) {
00432 int offset = 0;
00433 int cnt = 1;
00434
00435 if (elements.get(currentElement).properties.get(0).type2 != null) {
00436
00437 cnt = Integer.valueOf(parts[0]);
00438 offset = 1;
00439 } else {
00440 cnt = elements.get(currentElement).properties.size();
00441 }
00442
00443 ValueLine l = new ValueLine();
00444 for (int i = offset; i < cnt + offset; i++) {
00445 l.values.add(Float.valueOf(parts[i]));
00446 }
00447 elements.get(currentElement).lines.add(l);
00448 if (elements.get(currentElement).lines.size() == elements.get(currentElement).cnt)
00449 currentElement++;
00450 return true;
00451 }
00452
00462 private Number parseType(String type) {
00463 if (type.equals("char")) {
00464 return new Integer(byteBuffer.get());
00465 } else if (type.equals("uchar")) {
00466 return new Integer(byteBuffer.get());
00467 } else if (type.equals("short")) {
00468 short c = byteBuffer.getShort();
00469 return new Integer(c);
00470 } else if (type.equals("ushort")) {
00471 short c = byteBuffer.getShort();
00472 int v = new Integer(c);
00473 v += 32768;
00474 return new Integer(v);
00475 } else if (type.equals("int")) {
00476 return new Integer(byteBuffer.getInt());
00477 } else if (type.equals("uint")) {
00478 int v = byteBuffer.getInt();
00479 v += 2147483648l;
00480 return new Integer(v);
00481 } else if (type.equals("float")) {
00482 return new Float(byteBuffer.getFloat());
00483 } else if (type.equals("int")) {
00484 return new Float(byteBuffer.getDouble());
00485 } else {
00486 System.err.println("ERROR: invalid data type: " + type);
00487 return null;
00488 }
00489 }
00490
00497 private boolean processDataBuffer() {
00498
00499 for (int el = 0; el < elements.size(); el++) {
00500 for (int j = 0; j < elements.get(el).cnt; j++) {
00501 int valCnt;
00502 String listType = null;
00503 if (elements.get(el).properties.get(0).type2 != null) {
00504 listType = elements.get(el).properties.get(0).type2;
00505 valCnt = (Integer) parseType(elements.get(el).properties.get(0).type1);
00506 } else {
00507 listType = null;
00508 valCnt = elements.get(el).properties.size();
00509 }
00510
00511 ValueLine l = new ValueLine();
00512 for (int i = 0; i < valCnt; i++) {
00513 String type = listType;
00514 if (type == null) {
00515 type = elements.get(el).properties.get(i).type1;
00516 }
00517 l.values.add(parseType(type));
00518 }
00519 elements.get(el).lines.add(l);
00520 }
00521 }
00522 return true;
00523 }
00524 }