1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.geometry.euclidean.threed;
23
24 import java.io.BufferedReader;
25 import java.io.EOFException;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.text.ParseException;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33 import java.util.StringTokenizer;
34
35 import org.hipparchus.util.Precision;
36
37
38
39
40
41
42
43
44 public class PLYParser {
45
46
47 private Vector3D[] vertices;
48
49
50 private int[][] faces;
51
52
53 private BufferedReader br;
54
55
56 private String line;
57
58
59
60
61
62
63 public PLYParser(final InputStream stream)
64 throws IOException, ParseException {
65
66 try {
67 br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
68
69
70 List<Field> fields = parseNextLine();
71 if (fields.size() != 1 || fields.get(0).getToken() != Token.PLY) {
72 complain();
73 }
74
75 boolean parsing = true;
76 int nbVertices = -1;
77 int nbFaces = -1;
78 int xIndex = -1;
79 int yIndex = -1;
80 int zIndex = -1;
81 int vPropertiesNumber = -1;
82 boolean inVertexElt = false;
83 boolean inFaceElt = false;
84 while (parsing) {
85 fields = parseNextLine();
86 if (fields.size() < 1) {
87 complain();
88 }
89 switch (fields.get(0).getToken()) {
90 case FORMAT:
91 if (fields.size() != 3 ||
92 fields.get(1).getToken() != Token.ASCII ||
93 fields.get(2).getToken() != Token.UNKNOWN ||
94 !Precision.equals(Double.parseDouble(fields.get(2).getValue()), 1.0, 0.001)) {
95 complain();
96 }
97 inVertexElt = false;
98 inFaceElt = false;
99 break;
100 case COMMENT:
101
102 break;
103 case ELEMENT:
104 if (fields.size() != 3 ||
105 (fields.get(1).getToken() != Token.VERTEX && fields.get(1).getToken() != Token.FACE) ||
106 fields.get(2).getToken() != Token.UNKNOWN) {
107 complain();
108 }
109 if (fields.get(1).getToken() == Token.VERTEX) {
110 nbVertices = Integer.parseInt(fields.get(2).getValue());
111 inVertexElt = true;
112 inFaceElt = false;
113 } else {
114 nbFaces = Integer.parseInt(fields.get(2).getValue());
115 inVertexElt = false;
116 inFaceElt = true;
117 }
118 break;
119 case PROPERTY:
120 if (inVertexElt) {
121 ++vPropertiesNumber;
122 if (fields.size() != 3 ||
123 (fields.get(1).getToken() != Token.CHAR &&
124 fields.get(1).getToken() != Token.UCHAR &&
125 fields.get(1).getToken() != Token.SHORT &&
126 fields.get(1).getToken() != Token.USHORT &&
127 fields.get(1).getToken() != Token.INT &&
128 fields.get(1).getToken() != Token.UINT &&
129 fields.get(1).getToken() != Token.FLOAT &&
130 fields.get(1).getToken() != Token.DOUBLE)) {
131 complain();
132 }
133 if (fields.get(2).getToken() == Token.X) {
134 xIndex = vPropertiesNumber;
135 }else if (fields.get(2).getToken() == Token.Y) {
136 yIndex = vPropertiesNumber;
137 }else if (fields.get(2).getToken() == Token.Z) {
138 zIndex = vPropertiesNumber;
139 }
140 } else if (inFaceElt) {
141 if (fields.size() != 5 ||
142 fields.get(1).getToken() != Token.LIST &&
143 (fields.get(2).getToken() != Token.CHAR &&
144 fields.get(2).getToken() != Token.UCHAR &&
145 fields.get(2).getToken() != Token.SHORT &&
146 fields.get(2).getToken() != Token.USHORT &&
147 fields.get(2).getToken() != Token.INT &&
148 fields.get(2).getToken() != Token.UINT) ||
149 (fields.get(3).getToken() != Token.CHAR &&
150 fields.get(3).getToken() != Token.UCHAR &&
151 fields.get(3).getToken() != Token.SHORT &&
152 fields.get(3).getToken() != Token.USHORT &&
153 fields.get(3).getToken() != Token.INT &&
154 fields.get(3).getToken() != Token.UINT) ||
155 fields.get(4).getToken() != Token.VERTEX_INDICES) {
156 complain();
157 }
158 } else {
159 complain();
160 }
161 break;
162 case END_HEADER:
163 inVertexElt = false;
164 inFaceElt = false;
165 parsing = false;
166 break;
167 default:
168 throw new ParseException("unable to parse line: " + line, 0);
169 }
170 }
171 ++vPropertiesNumber;
172
173
174 vertices = new Vector3D[nbVertices];
175 for (int i = 0; i < nbVertices; ++i) {
176 fields = parseNextLine();
177 if (fields.size() != vPropertiesNumber ||
178 fields.get(xIndex).getToken() != Token.UNKNOWN ||
179 fields.get(yIndex).getToken() != Token.UNKNOWN ||
180 fields.get(zIndex).getToken() != Token.UNKNOWN) {
181 complain();
182 }
183 vertices[i] = new Vector3D(Double.parseDouble(fields.get(xIndex).getValue()),
184 Double.parseDouble(fields.get(yIndex).getValue()),
185 Double.parseDouble(fields.get(zIndex).getValue()));
186 }
187
188
189 faces = new int[nbFaces][];
190 for (int i = 0; i < nbFaces; ++i) {
191 fields = parseNextLine();
192 if (fields.isEmpty() ||
193 fields.size() != (Integer.parseInt(fields.get(0).getValue()) + 1)) {
194 complain();
195 }
196 faces[i] = new int[fields.size() - 1];
197 for (int j = 0; j < faces[i].length; ++j) {
198 faces[i][j] = Integer.parseInt(fields.get(j + 1).getValue());
199 }
200 }
201
202 } catch (NumberFormatException nfe) {
203 complain();
204 }
205 }
206
207
208
209
210 private void complain() throws ParseException {
211 throw new ParseException("unable to parse line: " + line, 0);
212 }
213
214
215
216
217
218
219 private List<Field> parseNextLine()
220 throws IOException, ParseException {
221 final List<Field> fields = new ArrayList<Field>();
222 line = br.readLine();
223 if (line == null) {
224 throw new EOFException();
225 }
226 final StringTokenizer tokenizer = new StringTokenizer(line);
227 while (tokenizer.hasMoreTokens()) {
228 fields.add(new Field(tokenizer.nextToken()));
229 }
230 return fields;
231 }
232
233
234
235
236 public List<Vector3D> getVertices() {
237 return Arrays.asList(vertices);
238 }
239
240
241
242
243 public List<int[]> getFaces() {
244 return Arrays.asList(faces);
245 }
246
247
248 private static enum Token {
249 PLY, FORMAT, ASCII, BINARY_BIG_ENDIAN, BINARY_LITTLE_ENDIAN,
250 COMMENT, ELEMENT, VERTEX, FACE, PROPERTY, LIST, OBJ_INFO,
251 CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE,
252 X, Y, Z, VERTEX_INDICES, END_HEADER, UNKNOWN;
253 }
254
255
256 private static class Field {
257
258
259 private final Token token;
260
261
262 private final String value;
263
264
265
266
267 public Field(final String value) {
268 Token parsedToken = null;
269 try {
270 parsedToken = Token.valueOf(value.toUpperCase());
271 } catch (IllegalArgumentException iae) {
272 parsedToken = Token.UNKNOWN;
273 }
274 this.token = parsedToken;
275 this.value = value;
276 }
277
278
279
280
281 public Token getToken() {
282 return token;
283 }
284
285
286
287
288 public String getValue() {
289 return value;
290 }
291
292 }
293
294 }