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