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