summaryrefslogtreecommitdiff
path: root/src/common/include/gudhi/iofile.h
blob: b939d45b46f578784a66ec4f6251dbe80d2787f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//todo remove and use off_reader instead

#ifndef GUDHI_IOFILE_H_
#define GUDHI_IOFILE_H_

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <list>
#include <cassert>



//todo use my new visitor based off instead
/**
 * @brief OFF reader, save the content of the file (vertices and maximal faces) in 'complex'.
 * The class Complex has to handle the following operations:
 * - void add_vertex(double[dim],int dim)
 * - void add_face(int dimension ,int[dimension] vertices)
 * Source from : http://www.holmes3d.net/graphics/offfiles/OFFLoading.txt
 *
 * @todo todo ignore comments in the file -> # comment
 */
template<typename Complex> inline
bool general_read_off_file(const std::string & file_name, Complex& complex){
  // Declare temporary variables to read data into.
  // If the read goes well, we'll copy these into
  // our class variables, overwriting what used to
  // be there. If it doesn't, we won't have messed up
  // our previous data structures.
  int tempNumPoints   = 0;  // Number of x,y,z coordinate triples
  int tempNumFaces    = 0;  // Number of polygon sets
  int tempNumEdges    = 0;  // Unused, except for reading.
  int tempDimPoints   = 0;
  double** tempPoints = NULL;  // An array of x,y,z coordinates.
  int** tempFaces = NULL;    // An array of arrays of point
  // pointers. Each entry in this
  // is an array of integers. Each
  // integer in that array is the
  // index of the x, y, and z
  // coordinates in the corresponding
  // arrays.
  int*  tempFaceSizes = NULL;  // An array of polygon point counts.
  // Each of the arrays in the tempFaces
  // array may be of different lengths.
  // This array corresponds to that
  // array, and gives their lengths.
  int i;        // Generic loop variable.
  bool goodLoad = true;    // Set to false if the file appears
  // not to be a valid OFF file.
  char tempBuf[128];    // A buffer for reading strings
  // from the file.

  // Create an input file stream for the file the CArchive
  // is connected to. This allows use of the overloaded
  // extraction operator for conversion from string
  // data to doubles and ints.
  std::ifstream ifs (file_name.c_str(), std::ios::in);
  if(!ifs.is_open()) {
    std::cerr << "Unable to open file " << file_name << std::endl;
    return false;
  }

  // Grab the first string. If it's "OFF", we think this
  // is an OFF file and continue. Otherwise we give up.
  ifs >> tempBuf;
  if (strcmp(tempBuf, "OFF") != 0) {
    goodLoad = false;
    std::cerr << "No OFF preambule\n";
  }

  // Read the sizes for our two arrays, and the third
  // int on the line. If the important two are zero
  // sized, this is a messed up OFF file. Otherwise,
  // we setup our temporary arrays.
  if (goodLoad) {
    ifs >> tempNumPoints >> tempNumFaces >> tempNumEdges;
    if (tempNumPoints < 1 || tempNumFaces < 0) {
      // If either of these were negative, we make
      // sure that both are set to zero. This is
      // important for later deleting our temporary
      // storage.
      goodLoad      = false;
      std::cerr << "tempNumPoints < 1 || tempNumFaces < 0\n";
      tempNumPoints = 0;
      tempNumFaces  = 0;
    } else {
      tempPoints = new double*[tempNumPoints];
      tempFaces = new int*[tempNumFaces];
      tempFaceSizes = new int[tempNumFaces];
    }
  }

  if (goodLoad) {
    // Load all of the points.

    // we start by loading the first one
    // the case is difference because then we dont know the dimension by advance
    // we discover the point dimension by reading the first line
    std::string lineFirstPoint;
	std::getline(ifs, lineFirstPoint);
    while(lineFirstPoint.size()<3){
    	std::getline(ifs, lineFirstPoint);
    }

    // we store the first point in a temporary list
    std::istringstream lineFirstPointStream(lineFirstPoint);
    std::list<double> firstTempPoint;
    double coord;
    while(lineFirstPointStream>>coord){
      firstTempPoint.push_back(coord);
      ++tempDimPoints;
    }
    // we store the point in our points array
    tempPoints[0]=new double[tempDimPoints];
    for( int j = 0 ; j<tempDimPoints; ++j){
      tempPoints[0][j] = firstTempPoint.front();
      firstTempPoint.pop_front();
    }

    // now, we know the dimension and can read safely other points
    for (i = 1; i < tempNumPoints; i++) {
      tempPoints[i] = new double[tempDimPoints];
      for (int j = 0 ; j<tempDimPoints ; ++j){
        ifs>>tempPoints[i][j];
      }
    }

    // Load all of the faces.
    for (i = 0; i < tempNumFaces; i++) {
      // This tells us how many points make up
      // this face.
      ifs >> tempFaceSizes[i];
      // So we declare a new array of that size
      tempFaces[i] = new int[tempFaceSizes[i]];
      // And load its elements with the vertex indices.
      for (int j = 0; j < tempFaceSizes[i]; j++) {
        ifs >> tempFaces[i][j];
      }
      // Clear out any face color data by reading up to
      // the newline. 128 is probably considerably more
      // space than necessary, but better safe than
      // sorry.
      ifs.getline(tempBuf, 128);
    }
  }

  // Here is where we copy the data from the temp
  // structures into our permanent structures. We
  // probably will do some more processing on the
  // data at the same time. This code you must fill
  // in on your own.
  if (goodLoad) {
    // we save vertices first in the complex
    for (i = 0; i < tempNumPoints; i++)
      complex.add_vertex(tempPoints[i],tempDimPoints);

    // we save faces
    for (i = 0; i < tempNumFaces; i++) {
      for (int j = 0; j < tempFaceSizes[i]; j++)
        complex.add_face(tempFaceSizes[i],tempFaces[i]);
    }
  }

  // Now that we're done, we have to make sure we
  // free our dynamic memory.
  for (i = 0; i < tempNumPoints; i++) {
    delete []tempPoints[i];
  }
  delete []tempPoints;

  for (i = 0; i < tempNumFaces; i++) {
    delete tempFaces[i];
  }
  delete []tempFaces;
  delete []tempFaceSizes;

  // Clean up our ifstream. The MFC framework will
  // take care of the CArchive.
  ifs.close();

  return goodLoad;
}


template<typename Complex>
class Geometric_flag_complex_wrapper{
  Complex& complex_;
  typedef typename Complex::Vertex_handle Vertex_handle;
  typedef typename Complex::Point Point;

  const bool load_only_points_;

public:
  Geometric_flag_complex_wrapper(Complex& complex,bool load_only_points = false):
    complex_(complex),
    load_only_points_(load_only_points)
{}


  void add_vertex(double* xyz,int dim){
    Point p(dim);
    for(int i=0;i<dim;++i)
      p[i] = xyz[i];
    complex_.add_vertex(p);
  }

  void add_face(int dimension ,int* vertices){
    if (!load_only_points_){
      for (int i = 0; i<dimension ; ++i)
        for (int j = i+1; j<dimension ; ++j)
          complex_.add_edge(Vertex_handle(vertices[i]),Vertex_handle(vertices[j]));
    }
  }
};




/**
 * @brief Read a mesh into a OFF file
 * load_only_points should be true if only the points have to be loaded.
 */
template<typename Complex>
bool read_off_file(std::string file_name,Complex &complex,bool load_only_points = false){
  complex.clear();
  Geometric_flag_complex_wrapper<Complex> complex_wrapper(complex,load_only_points);
  return general_read_off_file(file_name,complex_wrapper);

}


#endif