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