Reading stl file in C

Page 1 of 1

11 Replies - 5600 Views - Last Post: 16 July 2014 - 02:53 AM Rate Topic: -----

#1 nradam  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 56
  • Joined: 28-February 10

Reading stl file in C

Posted 06 June 2012 - 07:34 AM

Oye mates.
I am having a situation her :(
I am trying to read an stl file using C so that i can use it in another software called Dymola. Since dymola only takes C, i cannot use C++ to write the code btw.

So heres the thing, i made a code for reading one triangle in the stl file and it works pretty good. The task is to save the values in the stl file into two arrays. One arry is for the vertices of the triangle (meshing) and the other array is for the normal matrix.The program i wrote works except when the stl file has exponent values like "1.000000e+003". When such values are encountered, the program crashes.

I will give you guys a brief idea of how my program works. It reads an stl file using fgetc() so it is character by character. The values are stored in a variable called ch and then saved into a string. The strings are later converted into a double by atof() and then saved in the array. When i tried debugging the program, i found that the program crashes just after the + sign of the value like "1.000000e+003" is encountered. The ch takes a value [ 0 '\000' ] instead of [ 48 '0' ] which i have no idea why it happens. I will give you guys the code here and also an example stl. Just save the stl with some name like hello.stl and then you can run it as argument.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
	FILE *fp = fopen(argv[1], "r");
	char ch, k, chprev = 'a'; //a is a random character
	int z = 0, i1 = 0, i2 = 0, i3 = 0, k2 = 0;
	int loopx, loopy, loopn = 3;
	int endtri = 0; // makes sure that at end of one triangle chprev is 'a'
	char tempstring[25];
	double vectarr[3][3], normarr[1][3];

	if (fp == NULL) {
		printf("Cannot open file.\n");
		exit(1);
	}
	while ((ch = fgetc(fp)) != EOF) {

		if (ch == 'm') { //indicates beginning of a triangle
			z++;
			k = ch;
		} //Face Normal Matrix

		if (k == 'm' && ch == ' ' && chprev != ' ') { //indicates completion of a string
			if (z != 0) {
				vectarr[loopx][loopy] = atof(tempstring);
				if (loopn != 3)
					normarr[0][loopn] = atof(tempstring);
			}
			z++;
		}
		if (k == 'm' && z == 2 && ch != ' ') {
			tempstring[i1] = ch;
			i1++;
			tempstring[i1] = '\0';
			loopn = 0;
		} else if (k == 'm' && z == 3 && ch != ' ') {
			tempstring[i2] = ch;
			i2++;
			tempstring[i2] = '\0';
			loopn = 1;
		} else if (k == 'm' && z == 4 && ch != ' ') {
			tempstring[i3] = ch;
			i3++;
			tempstring[i3] = '\0';
			loopn = 2;
		}
		if (k2 == 0) {
			if (ch == 'x') {
				z = 1;
				k = ch;
				i1 = 0;
				i2 = 0;
				i3 = 0;
			} //Vertex1 Matrix
			if (k == 'x' && ch == ' ' && chprev != ' ')
				z++;
			if (k == 'x' && z == 2 && ch != ' ') {
				tempstring[i1] = ch;
				i1++;
				tempstring[i1] = '\0';
				loopx = 0;
				loopy = 0;
			} else if (k == 'x' && z == 3 && ch != ' ') {
				tempstring[i2] = ch;
				i2++;
				tempstring[i2] = '\0';
				loopx = 0;
				loopy = 1;
			} else if (k == 'x' && z == 4 && ch != ' ') {
				tempstring[i3] = ch;
				i3++;
				tempstring[i3] = '\0';
				loopx = 0;
				loopy = 2;
			} else if (k == 'x' && z == 5)
				k2 = 1;
		}

		if (k2 == 1) {
			if (ch == 'x') {
				z = 1;
				k = ch;
				i1 = 0;
				i2 = 0;
				i3 = 0;
			} //Vertex2 Matrix
			if (k == 'x' && ch == ' ' && chprev != ' ')
				z++;
			if (k == 'x' && z == 2 && ch != ' ') {
				tempstring[i1] = ch;
				i1++;
				tempstring[i1] = '\0';
				loopx = 1;
				loopy = 0;
			} else if (k == 'x' && z == 3 && ch != ' ') {
				tempstring[i2] = ch;
				i2++;
				tempstring[i2] = '\0';
				loopx = 1;
				loopy = 1;
			} else if (k == 'x' && z == 4 && ch != ' ') {
				tempstring[i3] = ch;
				i3++;
				tempstring[i3] = '\0';
				loopx = 1;
				loopy = 2;
			} else if (k == 'x' && z == 5)
				k2 = 2;
		}

		if (k2 == 2) {
			if (ch == 'x') {
				z = 1;
				k = ch;
				i1 = 0;
				i2 = 0;
				i3 = 0;
			} //Vertex3 Matrix
			if (k == 'x' && ch == ' ' && chprev != ' ')
				z++;
			if (k == 'x' && z == 2 && ch != ' ') {
				tempstring[i1] = ch;
				i1++;
				tempstring[i1] = '\0';
				loopx = 2;
				loopy = 0;
			} else if (k == 'x' && z == 3 && ch != ' ') {
				tempstring[i2] = ch;
				i2++;
				tempstring[i2] = '\0';
				loopx = 2;
				loopy = 1;
			} else if (k == 'x' && z == 4 && ch != ' ') {
				tempstring[i3] = ch;
				i3++;
				tempstring[i3] = '\0';
				loopx = 2;
				loopy = 2;
			} else if (k == 'x' && z == 5) { // Time to reinitialize
				z = 0, i1 = 0, i2 = 0, i3 = 0, k2 = 0, chprev = 'a';
				endtri = 1;
			}
		}
		if (endtri != 1)
			chprev = ch;

	}

	for (loopx = 0; loopx < 3; loopx++) {
		for (loopy = 0; loopy < 3; loopy++)
			printf("%f", vectarr[loopx][loopy]);
		printf("\n");
	}

	for (loopx = 0; loopx < 3; loopx++)
		printf("%f", normarr[0][loopx]);

	if (fp != NULL)
		fclose(fp);
	return 0;

}



Heres the stl i am using:

facet normal 0.000000e+000 0.000000e+000 1.000000e+000
outer loop
vertex 0.000000e+000 0.000000e+000 0.000000e+000
vertex -9.094947e-013 1.000000e+003 0.000000e+000
vertex 2.000000e+003 0.000000e+000 0.000000e+000
endloop

Thank you.

Btw since i am a beginner programmer, i dont have too much experience with programming. My buddy was saying its going to be hard to use C for stl files and instead use python stl parsors. I dont know what the hell is that, but if you guys can tell me more alternative and simple fast method to do the same thing i am doing now, that will be of great help.

With Regards
Adam

Is This A Good Question/Topic? 0
  • +

Replies To: Reading stl file in C

#2 jimblumberg  Icon User is online

  • member icon


Reputation: 4293
  • View blog
  • Posts: 13,459
  • Joined: 25-December 09

Re: Reading stl file in C

Posted 06 June 2012 - 07:41 AM

Is there a reason you are trying to read the file character by character, instead of using something like fscanf()?

Jim
Was This Post Helpful? 0
  • +
  • -

#3 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3666
  • View blog
  • Posts: 11,497
  • Joined: 05-May 12

Re: Reading stl file in C

Posted 06 June 2012 - 08:19 AM

View Postnradam, on 06 June 2012 - 07:34 AM, said:

I am trying to read an stl file using C so that i can use it in another software called Dymola. Since dymola only takes C, i cannot use C++ to write the code btw.


I can understand that if Dymola loaded your code as a DLL, or if it compiled and ran your code within its own system, but as best as I can tell from the product descriptions on their website, it doesn't.

If the code that you had attached was your entire program, then it shouldn't matter to Dymola whether your code was written in C, C++, C#, etc as long as the output you generate is in the correct format.
Was This Post Helpful? 0
  • +
  • -

#4 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3666
  • View blog
  • Posts: 11,497
  • Joined: 05-May 12

Re: Reading stl file in C

Posted 06 June 2012 - 09:18 AM

Actually, your program crashes at line 27 right after it reads the first space after "facet normal".

Let me give you a big hint: uninitialized variables.

Considering the number of variables you are trying to juggle to run your own little state machine parse the file, I'm not surprised that forgot to initialize some.

Once you fix the issue with line 27, take a closer look at your variable 'k'. It's uninitialized as well but the probabilities of it being randomly initialized to 'm' or 'x' is pretty slim so you've been getting lucky.

Jim is right. Consider using scanf() to simplify your code.

Or if you really insist on parsing the file one character at a time, consider parsing it in an active manner rather than passively with your adhoc state machine. For example like:
Expect(fp, 'facet');
Expect(fp, 'normal');
for(int i = 0; i < 3; ++i)
    normarr[0][i] = ReadFloat(fp);



This approach will not make your program as flexible, but at least it will make the code easier to read both on the high level, as well as let you just do one set of small things in the Expect() and ReadFloat() functions that you write.
Was This Post Helpful? 0
  • +
  • -

#5 nradam  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 56
  • Joined: 28-February 10

Re: Reading stl file in C

Posted 12 June 2012 - 04:08 AM

View Postjimblumberg, on 06 June 2012 - 02:41 PM, said:

Is there a reason you are trying to read the file character by character, instead of using something like fscanf()?

Jim


There was no reason lol. I just thought i will use fgetc and i kept programming until the system frigging blasted. I work as an internee at a company and since i was partying for a week, i didnt do my job. So i had to take a night out and i was programming when i should have slept :D

Anyways, depenting on the suggestion of you and others in this thread i went on with fscanf and coding was really simple. I got it done in like an hour or so. Allrite, but still have a few doubts.

a) I am dynamically allocating memory for every triangle in the stl file. Is it always required to free those memories? What if i dont free the memories, will it free by itself when i exit eclipse CDT.

B) When i debug the code (i am using mingw gcc), an error comes up at the end of the code saying :
[New Thread 3448.0xa38]
Quit (expect signal SIGINT when the program is resumed)

What the hell is that?

c) I am just parsing the stl file and storing the vertices and normals in two dynamic mutlidimensional arrays. But how do i know the values in the dynamic array? Usually i just debug and the values comes in the variables window. But this time, i think only the address of the pointers of the dynamic allocated memory is shown (i think) and not the value of the memory its pointing to. And thats frustrating because to see the values i have to print it out and that takes a lot more time and slows down my computer.

Thanks in advance. PEace
Was This Post Helpful? 0
  • +
  • -

#6 jimblumberg  Icon User is online

  • member icon


Reputation: 4293
  • View blog
  • Posts: 13,459
  • Joined: 25-December 09

Re: Reading stl file in C

Posted 12 June 2012 - 06:01 AM

Quote

I am dynamically allocating memory for every triangle in the stl file. Is it always required to free those memories?

Yes you should always free the memory you dynamically allocate.

Quote

When i debug the code (i am using mingw gcc), an error comes up at the end of the code saying :
[New Thread 3448.0xa38]
Quit (expect signal SIGINT when the program is resumed)

Post your current code along with the complete error message, exactly as it appears in your development environment.

Jim
Was This Post Helpful? 0
  • +
  • -

#7 nradam  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 56
  • Joined: 28-February 10

Re: Reading stl file in C

Posted 12 June 2012 - 08:08 AM

Heres the code like you asked. It would be awesome if you can help me with two things.
a ) I am not able to free the multidimensional memory location. When i tree to free them the program actually crashes. The three arrays i am trying to free are actually having no of rows i, 3i, i because i is the variable that is incremented everytime a new triangle is found in the stl file. The number of columns are always 3.

b ) I usually have to print the values in the dynamically allocated multidimensional array using printf to see it. But when i debug it and go to variables to see the values witout printing, only an array of 3 pointers (denoting the 3 columns) are shown while it must be having like lots and lots of values. How do i find the values of the dynamicaly allocated variables by debugging?

Thanks in advance


/* Attempt to parse stl file word by word */
// Some error in freeing memories

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define COLS 3                      //Defining a constant for number of columns
int main(int argc, char **argv) {
	FILE *fp = fopen(argv[1], "r"); //Opening file to read
	char string1[20];
	int loopx = 0, loopy = 0, loopn = 0;
	//int i1;
	double tmp;
	//int j1;
	//double vectarr[3][3];
	//double normarr[1][3];
	int i = 0;
	double (*vectarr)[COLS]; //Dynamic memory allocation
	double (*normarr)[COLS];
	double (*centerarr)[COLS];
	normarr = malloc(COLS * sizeof(double));
	if (normarr == NULL) {
		puts("Failure to allocate memory");
		exit(0);
	}
	vectarr = malloc(3 * COLS * sizeof(double));
	if (vectarr == NULL) {
		puts("Failure to allocate memory");
		exit(0);
	}
	centerarr = malloc(COLS * sizeof(double));
	if (centerarr == NULL) {
		puts("Failure to allocate memory");
		exit(0);
	}
	if (fp == NULL) {
		printf("Cannot open file.\n");
		exit(1);
	}

	while (fscanf(fp, "%s", string1) != EOF) { //The infinite loop
		if (strcmp(string1, "vertex")) //Parsing only the values
			if (strcmp(string1, "solid"))
				if (strcmp(string1, "endsolid"))
					if (strcmp(string1, argv[2]))
						if (strcmp(string1, "facet"))
							if (strcmp(string1, "normal"))
								if (strcmp(string1, "outer"))
									if (strcmp(string1, "loop"))
										if (strcmp(string1, "endloop"))
											if (strcmp(string1, "endfacet")) {

												//printf("%s\n", string1);
												//Saving the values into the dynamic array
												if (loopn == 3) {
													vectarr[3 * i + loopx][loopy] =
															atof(string1);
													loopy++;
													if (loopy == 3) {
														loopx++;
														loopy = 0;
													}
												}

												if (loopn != 3) {
													normarr[i][loopn] = atof(
															string1);
													loopn++;
												}

												if (loopn == 3 && loopx == 3) { //On to next triangle

													for (loopy = 0; loopy < 3;
															loopy++) {
														tmp = 0;
														for (loopx = 0;
																loopx < 3;
																loopx++)
															tmp =
																	tmp
																			+ vectarr[3
																					* i
																					+ loopx][loopy];
														tmp = tmp / 3;
														centerarr[i][loopy] =
																tmp;
													}

													loopx = 0;
													loopy = 0;
													loopn = 0;
													i++;

													double (*tmp1)[COLS] =
															realloc(normarr,
																	(i + 1)
																			* COLS
																			* sizeof(double)); //reallocating memory
													if (tmp1 != NULL)
														normarr = tmp1;
													else {
														fprintf(stderr,
																"Can't reallocate memory\n");
														/* dynarray remains allocated */
													}
													double (*tmp2)[COLS] =
															realloc(vectarr,
																	3 * (i + 1)
																			* COLS
																			* sizeof(double));
													if (tmp2 != NULL)
														vectarr = tmp2;
													else {
														fprintf(stderr,
																"Can't reallocate memory\n");
														/* dynarray remains allocated */
													}

													double (*tmp3)[COLS] =
															realloc(centerarr,
																	(i + 1)
																			* COLS
																			* sizeof(double)); //reallocating memory
													if (tmp3 != NULL)
														centerarr = tmp3;
													else {
														fprintf(stderr,
																"Can't reallocate memory\n");
														/* dynarray remains allocated */
													}

												}

											}
	}

	printf("Done"); //Indicating that the program is done.

	/*
	 for (i1 = 0; i1 < i; i1++) //Freeing dynamic memory ?
	 free(normarr[i1]);
	 free(normarr);
	 for (i1 = 0; i1 < 3*i; i1++)
	 free(vectarr[i1]);
	 free(vectarr);
	 for (i1 = 0; i1 < i; i1++)
	 free(centerarr[i1]);
	 free(centerarr);
	 */

	if (fp != NULL) //Closing the file
		fclose(fp);

	return 0;

}



And the SIGINT error somehow went away when i played with the code ;D
Also pass the name of the stl file and the solid name as arguments or the program wont work. If you want any example stl files to try on and the names of the arguments just ask me. Plus, i use eclipse CDT to code because i am usually coding android and java more :)

This post has been edited by nradam: 12 June 2012 - 08:15 AM

Was This Post Helpful? 0
  • +
  • -

#8 nradam  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 56
  • Joined: 28-February 10

Re: Reading stl file in C

Posted 13 June 2012 - 02:32 AM

Hey,

Question b ) of above is solved. You just have to go to right click the variables and then click on "display as array" and give the starting index and array length to get the value.

I am still waiting for an answer to question a )

This post has been edited by nradam: 13 June 2012 - 02:32 AM

Was This Post Helpful? 0
  • +
  • -

#9 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6111
  • View blog
  • Posts: 23,671
  • Joined: 23-August 08

Re: Reading stl file in C

Posted 13 June 2012 - 03:29 AM

while (fscanf(fp, "%s", string1) != EOF) { //The infinite loop
		if (strcmp(string1, "vertex")) //Parsing only the values
			if (strcmp(string1, "solid"))
				if (strcmp(string1, "endsolid"))
					if (strcmp(string1, argv[2]))
						if (strcmp(string1, "facet"))
							if (strcmp(string1, "normal"))
								if (strcmp(string1, "outer"))
									if (strcmp(string1, "loop"))
										if (strcmp(string1, "endloop"))
											if (strcmp(string1, "endfacet")) {

												//printf("%s\n", string1);
												//Saving the values into the dynamic array
												if (loopn == 3) {


You realize that strcmp returns 0 (false) if the strings match, right?

That's some ugly-ass code right there. What the hell are you trying to do with that code exactly?

There is actually no need for dynamic memory allocation here, because your allocation is all based on constant values.
Was This Post Helpful? 0
  • +
  • -

#10 nradam  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 56
  • Joined: 28-February 10

Re: Reading stl file in C

Posted 14 June 2012 - 04:51 AM

View PostJackOfAllTrades, on 13 June 2012 - 10:29 AM, said:

while (fscanf(fp, "%s", string1) != EOF) { //The infinite loop
		if (strcmp(string1, "vertex")) //Parsing only the values
			if (strcmp(string1, "solid"))
				if (strcmp(string1, "endsolid"))
					if (strcmp(string1, argv[2]))
						if (strcmp(string1, "facet"))
							if (strcmp(string1, "normal"))
								if (strcmp(string1, "outer"))
									if (strcmp(string1, "loop"))
										if (strcmp(string1, "endloop"))
											if (strcmp(string1, "endfacet")) {

												//printf("%s\n", string1);
												//Saving the values into the dynamic array
												if (loopn == 3) {


You realize that strcmp returns 0 (false) if the strings match, right?

That's some ugly-ass code right there. What the hell are you trying to do with that code exactly?

There is actually no need for dynamic memory allocation here, because your allocation is all based on constant values.


I did that because i wanted a working code and i had no other ideas. It needs to be changed asap, i know.
Anyway, i am trying to read only the real numbers from the stl file using fscanf. The stl file contains words and real numbers. So in that code was reading everything as string, discard all the words using that ugly-ass if statements and let only the real numbers get in (which i conver from strings to numbers using atof) so that i can save it in my array.

I need a dynamic memory allocation because the stl files might have a large number of triangles and everytime a triangle is encountered, the array has to be expanded to store the values.

For the same purpose of reading the real numbers, i tried doing something like this :
(while (fscanf(fp, "%f", realno) != EOF){   //CODE      }


but it doesnt seem to work. I dunno what to do. Help me with some ideas.

Below is an stl file with two triangles(meshing). Facet normal denotes the normal of the triangle and the vertex are the three vertices of the triangle. My task is to read only the real numbers in the file like this. What do i do?

solid CATIASTL
facet normal 0.000000e+000 0.000000e+000 1.000000e+000
outer loop
vertex 0.000000e+000 0.000000e+000 0.000000e+000
vertex -9.094947e-013 1.000000e+003 0.000000e+000
vertex 2.000000e+003 0.000000e+000 0.000000e+000
endloop
endfacet
facet normal 0.000000e+000 0.000000e+000 1.000000e+000
outer loop
vertex 2.000000e+003 0.000000e+000 0.000000e+000
vertex -9.094947e-013 1.000000e+003 0.000000e+000
vertex 2.000000e+003 1.000000e+003 0.000000e+000
endloop
endfacet
Was This Post Helpful? 0
  • +
  • -

#11 nradam  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 56
  • Joined: 28-February 10

Re: Reading stl file in C

Posted 14 June 2012 - 08:06 AM

I solved the problems i had here. Thank you for your help :)
Was This Post Helpful? 0
  • +
  • -

#12 cppUser_  Icon User is offline

  • New D.I.C Head

Reputation: -2
  • View blog
  • Posts: 1
  • Joined: 16-July 14

Re: Reading stl file in C

Posted 16 July 2014 - 02:53 AM

View Postnradam, on 14 June 2012 - 08:06 AM, said:

I solved the problems i had here. Thank you for your help :)/>

Hi I need STL reader ...can you post your working program?

Thank you,

Regards
cppUser_
Was This Post Helpful? -2
  • +
  • -

Page 1 of 1