1 /*******************************************************************************
2 Copyright (c) 2012, Jonathan Hiller
3
4 This file is part of the AMF Tools suite. http://amf.wikispaces.com/
5 AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6 AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
7 See <http://www.opensource.org/licenses/lgpl-3.0.html> for license details.
8 *******************************************************************************/
9
10 #include "STL_File.h"
11
12 #ifdef WIN32
13 #include <windows.h>
14 #endif
15 #include <stdio.h>
16
17 #include <GL/gl.h>
18 //#include <qgl.h>
19 //#include "QOpenGL.h"
20
21 //Elements adapted from vcg code...
22
23 double aWeldVertex::WeldThresh = 0;
24
25
26 #define STL_LABEL_SIZE 80
27
CSTL_File(void)28 CSTL_File::CSTL_File(void)
29 {
30 Clear();
31 }
32
~CSTL_File(void)33 CSTL_File::~CSTL_File(void)
34 {
35 }
36
37 //copy constructure
CSTL_File(CSTL_File & s)38 CSTL_File::CSTL_File(CSTL_File& s) {
39 *this = s;
40 }
41
42 //overload =
operator =(const CSTL_File & s)43 CSTL_File& CSTL_File::operator=(const CSTL_File& s) {
44
45 Facets.resize(s.Size());
46 int Size = Facets.size();
47 for (int i = 0; i<Size; i++)
48 Facets[i] = s.Facets[i];
49
50 return *this;
51 }
52
Load(std::string filename)53 bool CSTL_File::Load(std::string filename)
54 {
55 FILE *fp;
56 bool binary=false;
57 fp = fopen(filename.c_str(), "r");
58 if(fp == NULL) return false;
59
60 /* Find size of file */
61 fseek(fp, 0, SEEK_END);
62 int file_size = ftell(fp);
63 int facenum;
64 /* Check for binary or ASCII file */
65 fseek(fp, STL_LABEL_SIZE, SEEK_SET);
66 fread(&facenum, sizeof(int), 1, fp);
67 int expected_file_size=STL_LABEL_SIZE + 4 + (sizeof(short)+12*sizeof(float) )*facenum ;
68 if(file_size == expected_file_size) binary = true;
69 unsigned char tmpbuf[128];
70 fread(tmpbuf,sizeof(tmpbuf),1,fp);
71 for(unsigned int i = 0; i < sizeof(tmpbuf); i++){
72 if(tmpbuf[i] > 127){
73 binary=true;
74 break;
75 }
76 }
77 // Now we know if the stl file is ascii or binary.
78 fclose(fp);
79 bool RetVal;
80 if(binary) RetVal = LoadBinary(filename);
81 else RetVal = LoadAscii(filename);
82
83 if (RetVal) IsLoaded=true;
84
85 //extract object name from path
86 std::string NewObjName = filename;
87 int Start = NewObjName.find_last_of("\\/");
88 if (Start != std::string::npos) NewObjName = NewObjName.substr(Start + 1, NewObjName.size() - Start - 1);
89 int End = NewObjName.find_last_of(".");
90 if (End != std::string::npos) NewObjName = NewObjName.substr(0, End);
91 ObjectName = NewObjName;
92
93
94 return RetVal;
95 }
96
LoadBinary(std::string filename)97 bool CSTL_File::LoadBinary(std::string filename)
98 {
99 FILE *fp;
100 fp = fopen(filename.c_str(), "rb");
101 if(fp == NULL) return false;
102
103 int facenum;
104 fseek(fp, STL_LABEL_SIZE, SEEK_SET);
105 fread(&facenum, sizeof(int), 1, fp);
106
107 Clear();
108
109 // For each triangle read the normal, the three coords and a short set to zero
110 float N[3];
111 float P[9];
112 short attr;
113
114 for(int i=0;i<facenum;++i) {
115 fread(&N,3*sizeof(float),1,fp);
116 fread(&P,3*sizeof(float),3,fp);
117 fread(&attr,sizeof(short),1,fp);
118 AddFacet(N[0], N[1], N[2], P[0], P[1], P[2], P[3], P[4], P[5], P[6], P[7], P[8]);
119 }
120 fclose(fp);
121 return true;
122 }
123
LoadAscii(std::string filename)124 bool CSTL_File::LoadAscii(std::string filename)
125 {
126 FILE *fp;
127 fp = fopen(filename.c_str(), "r");
128 if(fp == NULL) return false;
129
130 long currentPos = ftell(fp);
131 fseek(fp,0L,SEEK_END);
132 long fileLen = ftell(fp);
133 fseek(fp,currentPos,SEEK_SET);
134
135 Clear();
136
137 /* Skip the first line of the file */
138 while(getc(fp) != '\n') { }
139
140 float N[3];
141 float P[9];
142 int cnt=0;
143 int lineCnt=0;
144 int ret;
145 /* Read a single facet from an ASCII .STL file */
146 while(!feof(fp)){
147 ret=fscanf(fp, "%*s %*s %f %f %f\n", &N[0], &N[1], &N[2]); // --> "facet normal 0 0 0"
148 if(ret!=3){
149 // we could be in the case of a multiple solid object, where after a endfaced instead of another facet we have to skip two lines:
150 // endloop
151 // endfacet
152 //endsolid <- continue on ret==0 will skip this line
153 //solid ascii <- and this one.
154 // facet normal 0.000000e+000 7.700727e-001 -6.379562e-001
155 lineCnt++;
156 continue;
157 }
158 ret=fscanf(fp, "%*s %*s"); // --> "outer loop"
159 ret=fscanf(fp, "%*s %f %f %f\n", &P[0], &P[1], &P[2]); // --> "vertex x y z"
160 if(ret!=3) return false;
161 ret=fscanf(fp, "%*s %f %f %f\n", &P[3], &P[4], &P[5]); // --> "vertex x y z"
162 if(ret!=3) return false;
163 ret=fscanf(fp, "%*s %f %f %f\n", &P[6], &P[7], &P[8]); // --> "vertex x y z"
164 if(ret!=3) return false;
165 ret=fscanf(fp, "%*s"); // --> "endloop"
166 ret=fscanf(fp, "%*s"); // --> "endfacet"
167 lineCnt+=7;
168 if(feof(fp)) break;
169
170 AddFacet(N[0], N[1], N[2], P[0], P[1], P[2], P[3], P[4], P[5], P[6], P[7], P[8]);
171
172 }
173 fclose(fp);
174 return true;
175 }
176
Save(std::string filename,bool Binary) const177 bool CSTL_File::Save(std::string filename, bool Binary) const { //writes ascii stl file...
178
179 FILE *fp;
180
181 if (Binary) fp = fopen(filename.c_str(),"wb");
182 else fp = fopen(filename.c_str(),"w");
183
184 if(fp==0) return false;
185 int NumFaces = (int)Facets.size();
186
187 if(Binary){
188 // Write Header
189 std::string tmp = ObjectName;
190 tmp += " ";
191 //char header[128]=;
192 fwrite(tmp.c_str(),80,1,fp);
193 // write number of facets
194 fwrite(&NumFaces,1,sizeof(int),fp);
195 unsigned short attributes=0;
196
197 for(int i=0; i<NumFaces; i++){
198 float N[3] = {(float)Facets[i].n.x, (float)Facets[i].n.y, (float)Facets[i].n.z};
199 float P[9] = {(float)Facets[i].v[0].x, (float)Facets[i].v[0].y, (float)Facets[i].v[0].z, (float)Facets[i].v[1].x, (float)Facets[i].v[1].y, (float)Facets[i].v[1].z, (float)Facets[i].v[2].x, (float)Facets[i].v[2].y, (float)Facets[i].v[2].z};
200
201 // For each triangle write the normal, the three coords and a short set to zero
202 fwrite(&N,3,sizeof(float),fp);
203 for(int k=0;k<3;k++){fwrite(&P[3*k],3,sizeof(float),fp);}
204 fwrite(&attributes,1,sizeof(short),fp);
205 }
206 }
207 else
208 {
209 fprintf(fp,"solid jdh\n");
210 for(int i=0; i<NumFaces; i++){
211 // For each triangle write the normal, the three coords and a short set to zero
212 fprintf(fp," facet normal %13e %13e %13e\n", Facets[i].n.x, Facets[i].n.y, Facets[i].n.z);
213 fprintf(fp," outer loop\n");
214 for(int k=0; k<3; k++){
215 fprintf(fp," vertex %13e %13e %13e\n", Facets[i].v[k].x, Facets[i].v[k].y, Facets[i].v[k].z);
216 }
217 fprintf(fp," endloop\n");
218 fprintf(fp," endfacet\n");
219 }
220 fprintf(fp,"endsolid vcg\n");
221 }
222 fclose(fp);
223
224 return 0;
225 }
226
227 //---------------------------------------------------------------------------
Draw(bool bModelhNormals,bool bShaded)228 void CSTL_File::Draw(bool bModelhNormals, bool bShaded)
229 //---------------------------------------------------------------------------
230 {
231 if (bShaded) {
232 glBegin(GL_TRIANGLES);
233 for (int i=0; i<(int)Facets.size(); i++) {
234 glNormal3d(Facets[i].n.x, Facets[i].n.y, Facets[i].n.z);
235 for (int j=0; j<3; j++) {
236 glVertex3d(Facets[i].v[j].x,Facets[i].v[j].y,Facets[i].v[j].z);
237 }
238 }
239 glEnd();
240 } else { // wireframe
241 for (int i=0; i<(int)Facets.size(); i++) {
242 glBegin(GL_LINE_LOOP);
243 glNormal3d(Facets[i].n.x, Facets[i].n.y, Facets[i].n.z);
244 for (int j=0; j<3; j++) {
245 glVertex3d(Facets[i].v[j].x,Facets[i].v[j].y,Facets[i].v[j].z);
246 }
247 glEnd();
248 }
249 }
250
251 if (bModelhNormals) {
252 glColor3d(1,1,0);
253 glBegin(GL_LINES);
254 for (int i=0; i<(int)Facets.size(); i++) {
255 Vec3D c = (Facets[i].v[0] + Facets[i].v[1] + Facets[i].v[2])/3;
256 Vec3D c2 = c - Facets[i].n*3;
257 glVertex3d(c.x, c.y, c.z);
258 glVertex3d(c2.x, c2.y, c2.z);
259 }
260 glEnd();
261 }
262
263 }
264
265 //---------------------------------------------------------------------------
ComputeBoundingBox(Vec3D & pmin,Vec3D & pmax)266 void CSTL_File::ComputeBoundingBox(Vec3D &pmin, Vec3D &pmax)
267 //---------------------------------------------------------------------------
268 {
269 if (Facets.size() == 0)
270 return;
271
272 pmin = pmax = Facets[0].v[0];
273
274 for (int i=0; i<(int)Facets.size(); i++) {
275 for (int j=0; j<3; j++) {
276 pmin.x = (std::min)(pmin.x, Facets[i].v[j].x);
277 pmin.y = (std::min)(pmin.y, Facets[i].v[j].y);
278 pmin.z = (std::min)(pmin.z, Facets[i].v[j].z);
279 pmax.x = (std::max)(pmax.x, Facets[i].v[j].x);
280 pmax.y = (std::max)(pmax.y, Facets[i].v[j].y);
281 pmax.z = (std::max)(pmax.z, Facets[i].v[j].z);
282 }
283 }
284
285 }
286
GetSize()287 Vec3D CSTL_File::GetSize()
288 {
289 Vec3D min, max;
290 ComputeBoundingBox(min, max);
291 return max-min;
292 }
293
294 /*
295 //---------------------------------------------------------------------------
296 void CSTL_File::Translate(CVec d)
297 //---------------------------------------------------------------------------
298 {// translate geometry
299
300 for (int i=0; i<Facets.size(); i++) {
301 for (int j=0; j<3; j++) {
302 Facets[i].v[j] += d;
303 }
304 }
305
306 }
307
308 //---------------------------------------------------------------------------
309 void CSTL_File::Scale(CVec s)
310 //---------------------------------------------------------------------------
311 {// scale geometry
312
313 //check for zero scale factor
314 if(s.x==0 || s.y==0 || s.z==0) return;
315 for (int i=0; i<Facets.size(); i++) {
316 for (int j=0; j<3; j++) {
317 Facets[i].v[j].x *= s.x;
318 Facets[i].v[j].y *= s.y;
319 Facets[i].v[j].z *= s.z;
320 }
321 Facets[i].n.x *= s.x;
322 Facets[i].n.y *= s.y;
323 Facets[i].n.z *= s.z;
324 /// Facets[i].n.Normalize();
325 }
326
327 }
328
329 //---------------------------------------------------------------------------
330 void CSTL_File::Rotate(CVec ax, double a)
331 //---------------------------------------------------------------------------
332 {
333
334 for (int i=0; i<Facets.size(); i++) {
335 for (int j=0; j<3; j++) {
336 Facets[i].v[j] = Facets[i].v[j].Rot(ax, a);
337 }
338 Facets[i].n = Facets[i].n.Rot(ax, a);
339 }
340
341 }
342
343 //---------------------------------------------------------------------------
344 void CSTL_File::RotX(double a)
345 //---------------------------------------------------------------------------
346 {
347
348 for (int i=0; i<Facets.size(); i++) {
349 for (int j=0; j<3; j++) {
350 Facets[i].v[j].RotX(a);
351 }
352 Facets[i].n.RotX(a);
353 }
354
355 }
356
357
358 //---------------------------------------------------------------------------
359 void CSTL_File::RotY(double a)
360 //---------------------------------------------------------------------------
361 {
362
363 for (int i=0; i<Facets.size(); i++) {
364 for (int j=0; j<3; j++) {
365 Facets[i].v[j].RotY(a);
366 }
367 Facets[i].n.RotY(a);
368 }
369
370 }
371
372
373 //---------------------------------------------------------------------------
374 void CSTL_File::RotZ(double a)
375 //---------------------------------------------------------------------------
376 {
377
378 for (int i=0; i<Facets.size(); i++) {
379 for (int j=0; j<3; j++) {
380 Facets[i].v[j].RotZ(a);
381 }
382 Facets[i].n.RotZ(a);
383 }
384
385 }
386 */
387