-
Notifications
You must be signed in to change notification settings - Fork 211
/
Copy pathSTLReader.hpp
237 lines (211 loc) · 6.58 KB
/
STLReader.hpp
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
/*************************************************************************
* Copyright (C) 2008 by Sergei Dorofeenko *
* *
* This program is free software; it is licensed under the terms of the *
* GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/
#pragma once
#include <stdio.h>
#include<string.h>
#include <set>
#include <vector>
#include <cmath>
#include "utils.hpp"
using namespace std;
class STLReader {
public:
// if it is binary there are 80 char of comment, the number fn of faces and then exactly fn*4*3 bytes.
enum {STL_LABEL_SIZE=80};
template<class OutV, class OutE, class OutF, class OutN>
bool open(const char* filename, OutV vertices, OutE edges, OutF facets, OutN normals);
float tolerance;
protected:
template<class OutV, class OutE, class OutF, class OutN>
bool open_binary(const char* filename, OutV vertices, OutE edges, OutF facets, OutN normals);
template<class OutV, class OutE, class OutF, class OutN>
bool open_ascii(const char* filename, OutV vertices, OutE edges, OutF facets, OutN normals);
struct Vrtx {
float pos[3];
Vrtx(){}
Vrtx(float x, float y, float z) {pos[0]=x; pos[1]=y; pos[2]=z;}
bool operator< (const Vrtx& v) const
{
return memcmp(pos, v.pos,3*sizeof(float)) < 0;
}
float operator[](int id) const { return pos[id]; }
float& operator[](int id) { return pos[id]; }
};
class IsDifferent {
float tolerance;
public:
IsDifferent(float _tolerance): tolerance(_tolerance){}
bool operator() (const Vrtx& v1, const Vrtx& v2)
{
if ( std::abs(v1[0]-v2[0])<tolerance
&& std::abs(v1[1]-v2[1])<tolerance
&& std::abs(v1[2]-v2[2])<tolerance )
return false;
return true;
}
};
};
template<class OutV, class OutE, class OutF, class OutN>
bool STLReader::open(const char* filename, OutV vertices, OutE edges, OutF facets, OutN normals)
{
FILE *fp;
bool binary=false;
fp = fopen(filename, "r");
if(fp == NULL)
return false;
/* Find size of file */
fseek(fp, 0, SEEK_END);
int file_size = ftell(fp);
int facenum;
/* Check for binary or ASCII file */
fseek(fp, STL_LABEL_SIZE, SEEK_SET);
size_t res=fread(&facenum, sizeof(int), 1, fp);
int expected_file_size=STL_LABEL_SIZE + 4 + (sizeof(short)+4*sizeof(float) )*facenum ;
if(file_size == expected_file_size) binary = true;
unsigned char tmpbuf[128];
res=fread(tmpbuf,sizeof(tmpbuf),1,fp);
if (res)
{
for(size_t i = 0; i < sizeof(tmpbuf); i++)
{
if(tmpbuf[i] > 127)
{
binary=true;
break;
}
}
}
// Now we know if the stl file is ascii or binary.
fclose(fp);
if(binary) return open_binary(filename,vertices,edges,facets,normals);
else return open_ascii(filename,vertices,edges,facets,normals);
}
template<class OutV, class OutE, class OutF, class OutN>
bool STLReader::open_ascii(const char* filename, OutV vertices, OutE edges, OutF facets, OutN normals)
{
FILE *fp;
fp = fopen(filename, "r");
if(fp == NULL)
return false;
/* Skip the first line of the file */
while(getc(fp) != '\n');
vector<Vrtx> vcs;
set<pair<int,int> > egs;
size_t ret;
/* Read a single facet from an ASCII .STL file */
while(!feof(fp))
{
float n[3];
Vrtx v[3];
ret=fscanf(fp, "%*s %*s %f %f %f\n", &n[0], &n[1], &n[2]);
ret=fscanf(fp, "%*s %*s");
ret=fscanf(fp, "%*s %f %f %f\n", &v[0][0], &v[0][1], &v[0][2]);
ret=fscanf(fp, "%*s %f %f %f\n", &v[1][0], &v[1][1], &v[1][2]);
ret=fscanf(fp, "%*s %f %f %f\n", &v[2][0], &v[2][1], &v[2][2]);
ret=fscanf(fp, "%*s"); // end loop
ret=fscanf(fp, "%*s"); // end facet
if(ret < 0 || feof(fp)) break;
int vid[3];
for(int i=0;i<3;++i)
{
(normals++) = n[i];
bool is_different=true;
IsDifferent isd(tolerance);
int j=0;
for(int ej=vcs.size(); j<ej; ++j)
if ( !(is_different = isd(v[i],vcs[j])) ) break;
if (is_different)
{
vid[i] = vcs.size();
vcs.push_back(v[i]);
}
else
vid[i] = j;
(facets++) = vid[i];
}
egs.insert(minmax(vid[0], vid[1]));
egs.insert(minmax(vid[1], vid[2]));
egs.insert(minmax(vid[2], vid[0]));
}
fclose(fp);
for(vector<Vrtx>::iterator it=vcs.begin(),end=vcs.end(); it!=end; ++it)
{
(vertices++) = (*it)[0];
(vertices++) = (*it)[1];
(vertices++) = (*it)[2];
}
for(set<pair<int,int> >::iterator it=egs.begin(),end=egs.end(); it!=end; ++it)
{
(edges++) = it->first;
(edges++) = it->second;
}
return true;
}
template<class OutV, class OutE, class OutF, class OutN>
bool STLReader::open_binary(const char* filename, OutV vertices, OutE edges, OutF facets, OutN normals)
{
FILE *fp;
fp = fopen(filename, "rb");
if(fp == NULL)
{
return false;
}
int facenum;
fseek(fp, STL_LABEL_SIZE, SEEK_SET);
int res=fread(&facenum, sizeof(int), 1, fp);
vector<Vrtx> vcs;
set<pair<int,int> > egs;
if (res)
{
// For each triangle read the normal, the three coords and a short set to zero
for(int i=0;i<facenum;++i)
{
short attr;
float n[3];
Vrtx v[3];
res=fread(&n,3*sizeof(float),1,fp);
res=fread(&v,sizeof(Vrtx),3,fp);
res=fread(&attr,sizeof(short),1,fp);
//FIXME: Убрать дублирование кода с open_ascii
int vid[3];
for(int i=0;i<3;++i)
{
(normals++) = n[i];
bool is_different=true;
IsDifferent isd(tolerance);
int j=0;
for(int ej=vcs.size(); j<ej; ++j)
if ( !(is_different = isd(v[i],vcs[j])) ) break;
if (is_different)
{
vid[i] = vcs.size();
vcs.push_back(v[i]);
}
else
vid[i] = j;
(facets++) = vid[i];
}
egs.insert(minmax(vid[0], vid[1]));
egs.insert(minmax(vid[1], vid[2]));
egs.insert(minmax(vid[2], vid[0]));
}
}
fclose(fp);
for(vector<Vrtx>::iterator it=vcs.begin(),end=vcs.end(); it!=end; ++it)
{
(vertices++) = (*it)[0];
(vertices++) = (*it)[1];
(vertices++) = (*it)[2];
}
for(set<pair<int,int> >::iterator it=egs.begin(),end=egs.end(); it!=end; ++it)
{
(edges++) = it->first;
(edges++) = it->second;
}
return true;
}