$search
00001 /******************************************************************************* 00002 * Copyright (c) 2012 Stefan Profanter. All rights reserved. This program and the accompanying 00003 * materials are made available under the terms of the GNU Public License v3.0 which accompanies 00004 * this distribution, and is available at http://www.gnu.org/licenses/gpl.html 00005 * 00006 * Contributors: Stefan Profanter - initial API and implementation, Year: 2012 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 // dump(); 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 // it is list 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; // TODO not yet tested 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; // TODO not yet tested 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 }