1 /****************************************************************************
2 * VCGLib o o *
3 * Visual and Computer Graphics Library o o *
4 * _ O _ *
5 * Copyright(C) 2004-2016 \/)\/ *
6 * Visual Computing Lab /\/| *
7 * ISTI - Italian National Research Council | *
8 * \ *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20 * for more details. *
21 * *
22 ****************************************************************************/
23
24 /****************************************************************************
25 History
26
27 $Log: not supported by cvs2svn $
28 Revision 1.2 2005/05/09 12:29:55 callieri
29 added line cleaning to eliminate all separators, added a rough triangulation scheme.
30
31 Revision 1.1 2005/05/06 13:58:26 callieri
32 First working version (callieri)
33
34
35 ****************************************************************************/
36
37 #ifndef __VCGLIB_IMPORT_RAW
38 #define __VCGLIB_IMPORT_RAW
39
40 #include <stdio.h>
41 #include <fstream>
42 #include <iostream>
43
44 namespace vcg {
45 namespace tri {
46 namespace io {
47
48 /**
49 This class encapsulate a filter for importing raw format pointcloud.
50 there exists many raw formats. each one with a particular sintax even if they only contains
51
52 */
53 template <class MESH_TYPE>
54 class ImporterRAW
55 {
56 public:
57
58 typedef typename MESH_TYPE::VertexPointer VertexPointer;
59 typedef typename MESH_TYPE::ScalarType ScalarType;
60 typedef typename MESH_TYPE::VertexType VertexType;
61 typedef typename MESH_TYPE::FaceType FaceType;
62 typedef typename MESH_TYPE::VertexIterator VertexIterator;
63 typedef typename MESH_TYPE::FaceIterator FaceIterator;
64
65 // max token number
66 #define RAW_MAX_TOKEN_LINE_DESCRIPTOR 32
67
68
69 enum RAWError {
70 E_NOERROR, // 0
71 // Error open
72 E_CANTOPEN, // 1
73 E_UNESPECTEDEOF, // 2
74 // error line descriptor
75 E_INVALIDLINEDESC, // 3
76 // error line parsing
77 E_LINEERROR, // 4
78 // wrong number of points
79 E_WRONGPOINTNUM // 5
80 };
81
ErrorMsg(int error)82 static const char *ErrorMsg(int error)
83 {
84 static const char * raw_error_msg[] =
85 {
86 "No errors",
87 "Can't open file",
88 "Premature End of file",
89 "Invalid line Descriptor",
90 "Error parsing a line",
91 "Point number different from expected"
92 };
93
94 if(error>2 || error<0) return "Unknown error";
95 else return stl_error_msg[error];
96 };
97
98 // line format is a string describing which data is stored for every data line
99 // PX PY PZ posizione
100 // NX NY NZ normale
101 // CR CG CB colore
102 // RF riflettanza (qualita')
103 //
104 // the string is parsed to know how many value are contained in each line
105 // and which is the order. the result is a number (how many) and a vector
106 // describing the order
107 //
108 //
109 // during reading a data structure is used to store intermediate values
110 // it is basically an array of float
111 //
112 // float linebuffer[]
113 //[0][1][2][3][4][5][6][7][8][9]
114 // p p p n n n c c c r
115 // x y z x y z r g b f
116 //
117 // given the number of tokens and the order vector it is possible to scan a line using the command
118 //
119 // for(...n 0->tokennumber...)
120 // fscanf(fp,"%f", &linebuffer[tokenorder[n]])
121
Parselinedescription(const char * linedesc,int & tokennumber,int * order)122 static int Parselinedescription(const char * linedesc, int &tokennumber, int *order)
123 {
124 int ii;
125 char tok[3];
126 int index;
127
128 // controllo lunghezza
129 // se non e' multiplo di 3 allora e' errato
130 int len = strlen(linedesc) + 1;
131 if(len%3 != 0)
132 return E_INVALIDLINEDESC;
133
134 index=0;
135 tok[2] = '\0';
136 tokennumber = 0;
137 for(ii=0; ii<RAW_MAX_TOKEN_LINE_DESCRIPTOR; ii++)
138 order[ii] = -1;
139
140 while(index <= (len-3))
141 {
142 tok[0] = linedesc[index ];
143 tok[1] = linedesc[index+1];
144
145 if(strcmp(tok,"PX") == 0) // pos x
146 {order[tokennumber] = 0; tokennumber++;}
147 else if (strcmp(tok,"PY") == 0) // pos y
148 {order[tokennumber] = 1; tokennumber++;}
149 else if (strcmp(tok,"PZ") == 0) // pos z
150 {order[tokennumber] = 2; tokennumber++;}
151 else if (strcmp(tok,"NX") == 0) // norm x
152 {order[tokennumber] = 3; tokennumber++;}
153 else if (strcmp(tok,"NY") == 0) // norm y
154 {order[tokennumber] = 4; tokennumber++;}
155 else if (strcmp(tok,"NZ") == 0) // norm z
156 {order[tokennumber] = 5; tokennumber++;}
157 else if (strcmp(tok,"CR") == 0) // col r
158 {order[tokennumber] = 6; tokennumber++;}
159 else if (strcmp(tok,"CG") == 0) // col g
160 {order[tokennumber] = 7; tokennumber++;}
161 else if (strcmp(tok,"CB") == 0) // col b
162 {order[tokennumber] = 8; tokennumber++;}
163 else if (strcmp(tok,"RF") == 0) // rifl
164 {order[tokennumber] = 9; tokennumber++;}
165 else // nessuno dei suddetti... errore
166 { return E_INVALIDLINEDESC; }
167
168 index +=3;
169 }
170
171 return E_NOERROR;
172 }
173
174
175 // function to skip a line
Skipline(FILE * fp)176 static void Skipline(FILE *fp)
177 {
178 char buf;
179
180 fread(&(buf),sizeof(char),1,fp);
181
182 while(buf != '\n')
183 fread(&(buf),sizeof(char),1,fp);
184 }
185
186 // function to parse the line read from the raw file
187 // all characters besides numerals,dot,minus,plus
188 // if e is found between numbers it's ketpt (12e4)
Parseline(int tokennumber,int * tokenorder,char * rawline,float * linebuffer)189 static int Parseline(int tokennumber, int *tokenorder, char *rawline, float *linebuffer)
190 {
191 int linelen;
192 int ii;
193 bool change;
194 int foundtok;
195
196 // length
197 linelen = strlen(rawline);
198
199 // cleaning the line
200 for(ii=0;ii<(linelen-1);)
201 {
202 change = true;
203
204 if(isdigit(rawline[ii])) // is a number
205 change = false;
206 else if(rawline[ii]==' ') // is a space
207 change = false;
208 else if((rawline[ii]=='-') || (rawline[ii]=='+') || (rawline[ii]=='-') || (rawline[ii]=='.')) // is + - .
209 change = false;
210 else if(rawline[ii]=='e') // is e... is perhaps an exponential ?
211 {
212 if((ii>0) || (ii<(linelen-2))) // if it's at the begin or the end of line, it's not an exponential
213 if(isdigit(rawline[ii-1])) // a number before it
214 if(isdigit(rawline[ii+1]) || (rawline[ii+1]=='+') || (rawline[ii+1]=='-')) // after it a number a plus or a minus
215 change = false;
216 }
217
218 if(change)
219 rawline[ii++] = ' '; // then change it to ' '
220 else
221 ii++;
222
223 }
224 rawline[linelen] = '\0';
225
226 // now parsing the line
227 foundtok = 0;
228 ii = 0;
229 while((foundtok<tokennumber)&&(ii<linelen))
230 {
231 //find the next token begin
232 while(rawline[ii] == ' ')
233 ii++;
234
235 foundtok++;
236 sscanf(&(rawline[ii]),"%f", &(linebuffer[tokenorder[foundtok-1]]));
237
238 // going after the token
239 while((rawline[ii] != ' ')&&(rawline[ii] != '\0'))
240 ii++;
241 }
242
243 if(foundtok<tokennumber)
244 return E_LINEERROR;
245 else
246 return E_NOERROR;
247 }
248
249
fillHoles(MESH_TYPE & m,size_t rowCount,size_t colCount)250 static int fillHoles( MESH_TYPE &m, size_t rowCount, size_t colCount)
251 {
252
253 for (size_t i = 1; i<colCount-1; ++i)
254 for (size_t j = 1; j<rowCount-1; ++j)
255 {
256
257 size_t ind = (i) + ((j) * colCount);
258 size_t indL = (i-1) + ((j) * colCount);
259 size_t indR = (i+1) + ((j) * colCount);
260 size_t indT = (i) + ((j-1) * colCount);
261 size_t indB = (i) + ((j+1) * colCount);
262
263 if ((m.vert[ind].P() == vcg::Point3<MESH_TYPE::ScalarType>(0,0,0)) &&
264 (m.vert[indL].P() != vcg::Point3<MESH_TYPE::ScalarType>(0,0,0)) &&
265 (m.vert[indR].P() != vcg::Point3<MESH_TYPE::ScalarType>(0,0,0)) &&
266 (m.vert[indT].P() != vcg::Point3<MESH_TYPE::ScalarType>(0,0,0)) &&
267 (m.vert[indB].P() != vcg::Point3<MESH_TYPE::ScalarType>(0,0,0)) )
268 {
269 m.vert[ind].P() = ( m.vert[indL].P() + m.vert[indR].P() + m.vert[indT].P() + m.vert[indB].P() ) * 0.25;
270
271 }
272
273
274 }
275
276 //vcg::tri::io::ExporterPLY<MESH_TYPE>::Save( hm, "hole.ply" );
277 return 1;
278 }
279
280 /*!
281 * Standard call for reading a mesh
282 * \param m the destination mesh
283 * \param filename the name of the file to read from
284 * \param triangulate if true, the mesh will be triangulated, otherwise only points will be stored
285 * \param lineskip number of lines to be skipped at the begin of the file
286 * \return the operation result
287 */
288 static int Open( MESH_TYPE &m, const char * filename, bool triangulate=false, int lineskip = 0, const char * linedesc = "PX PY PZ")
289 {
290 int ii;
291 int ret;
292
293
294 FILE *fp;
295 int rownumber;
296 int colnumber;
297
298 // line description
299 int tokennumber;
300 int tokenorder[RAW_MAX_TOKEN_LINE_DESCRIPTOR];
301
302 // line read from file, to be parsed
303 char rawline[512];
304
305
306
307 //line data buffer
308 float linebuffer[10];
309 // fill buffer with standard values
310 linebuffer[0] = linebuffer[1] = linebuffer[2] = 0.0;
311 linebuffer[3] = linebuffer[4] = linebuffer[5] = 1.0;
312 linebuffer[6] = 0.0; linebuffer[7] = 1.0; linebuffer[8] = 0.0;
313 linebuffer[9] = 1.0;
314
315
316 fp = fopen(filename, "r");
317
318 if(fp == NULL)
319 {
320 return E_CANTOPEN;
321 }
322
323 // skip initial lines
324 for(ii=0; ii<lineskip; ii++) Skipline(fp);
325
326 // in raw files with indication of rows and columns it's also possible to triangulate points
327 // after the skipped lines there should be the number of row and columns
328 if(triangulate)
329 {
330 fscanf(fp,"%i", &(rownumber));
331 fscanf(fp,"%i\n", &(colnumber));
332 }
333
334 // parsing line description
335 ret = Parselinedescription(linedesc, tokennumber, tokenorder);
336 if(ret)
337 return ret;
338
339 m.Clear();
340 m.vert.reserve( rownumber * colnumber );
341 int line = 0;
342 size_t rowCounter = 0;
343 size_t colCounter = 0;
344 while(!feof(fp))
345 {
346 /**/
347 //read a new line
348
349 ii=0;
350 memset( rawline, 0, 512);
351 fread(&(rawline[ii++]),sizeof(char),1,fp);
352 while( (rawline[ii-1] != '\n') && (ii<512) )
353 {
354 fread(&(rawline[ii++]),sizeof(char),1,fp);
355 }
356 rawline[ii-1] = '\0';
357 line++;
358 if(strlen(rawline) >0) // empty line, just skip
359 {
360
361 ret = Parseline(tokennumber, tokenorder, rawline, linebuffer);
362 if(ret)
363 return ret;
364
365 /*
366 // old code reading directly fom file stream
367 for(ii=0; ii<tokennumber; ii++)
368 fscanf(fp,"%f", &(linebuffer[tokenorder[ii]]));
369 */
370
371 // new vertex
372 VertexType nv;
373
374 // store the position
375 nv.P()[0] = linebuffer[0];
376 nv.P()[1] = linebuffer[1];
377 nv.P()[2] = linebuffer[2];
378
379 // store the normal
380 if(HasPerVertexNormal(m))
381 {
382 nv.N()[0] = linebuffer[3];
383 nv.N()[1] = linebuffer[4];
384 nv.N()[2] = linebuffer[5];
385 }
386
387 // store the color
388 if(HasPerVertexColor(m))
389 {
390 nv.C()[0] = linebuffer[6];
391 nv.C()[1] = linebuffer[7];
392 nv.C()[2] = linebuffer[8];
393 }
394
395 // store the reflectance
396 if(m.HasPerVertexQuality())
397 {
398 nv.Q() = linebuffer[9];
399 }
400
401 m.vert.push_back(nv);
402
403
404
405 } // end if zero length
406 }
407 m.vn = m.vert.size();
408 if(triangulate) fillHoles(m, rownumber, colnumber);
409
410 // update model point number
411
412
413 // now generate the triangles
414 if(triangulate)
415 {
416 int rr,cc;
417 //if(m.vn != (rownumber * colnumber)) return E_WRONGPOINTNUM;
418
419 int trinum = (rownumber-1) * (colnumber-1) * 2;
420
421 FaceIterator fi=Allocator<MESH_TYPE>::AddFaces(m,trinum);
422 FaceIterator fi2 = fi;
423 m.fn = trinum;
424 for(cc=0; cc<colnumber-1; cc++)
425 for(rr=0; rr<rownumber-1; rr++)
426 {
427 // upper tri
428 (*fi).V(0) = &(m.vert[(cc+1) + ((rr ) * colnumber)]);
429 (*fi).V(1) = &(m.vert[(cc ) + ((rr ) * colnumber)]);
430 (*fi).V(2) = &(m.vert[(cc ) + ((rr+1) * colnumber)]);
431
432
433 fi++;
434
435 // lower tri
436 (*fi).V(0) = &(m.vert[(cc ) + ((rr+1) * colnumber)]);
437 (*fi).V(1) = &(m.vert[(cc+1) + ((rr+1) * colnumber)]);
438 (*fi).V(2) = &(m.vert[(cc+1) + ((rr ) * colnumber)]);
439
440 fi++;
441
442 }
443
444 // tag faux faces
445 if (m.HasPerFaceFlags()) {
446 for (; fi2!=m.face.end(); fi2++) {
447 (*fi2).SetF(2);
448 }
449 }
450
451
452
453 }
454
455 fclose(fp);
456 return E_NOERROR;
457 }
458
459 }; // end class
460 } // end Namespace tri
461 } // end Namespace io
462 } // end Namespace vcg
463
464 #endif
465