Skip to content

Commit eae7b83

Browse files
committed
updated logic to handle binary STL files with "solid" in the header
1 parent ad7bccb commit eae7b83

File tree

6 files changed

+114
-19
lines changed

6 files changed

+114
-19
lines changed

libs/license/cyanobacterium⁄STL-Parser-for-Java/LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2014 cyanobacteruim
3+
Copyright (c) 2014 cyanobacteruim, 2017 andrew goh
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

src/hall/collin/christopher/stl4j/LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2014 cyanobacteruim
3+
Copyright (c) 2014 cyanobacteruim, 2017 andrew goh
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

src/hall/collin/christopher/stl4j/STLParser.java

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2014 CCHall (aka Cyanobacterium aka cyanobacteruim)
4+
Copyright (c) 2014 CCHall (aka Cyanobacterium aka cyanobacteruim), 2017 Andrew Goh
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal
@@ -33,15 +33,24 @@ of this software and associated documentation files (the "Software"), to deal
3333
import java.nio.file.Files;
3434
import java.nio.file.Path;
3535
import java.util.ArrayList;
36+
import java.util.Arrays;
3637
import java.util.List;
38+
import java.util.StringTokenizer;
3739
import java.util.logging.Level;
3840
import java.util.logging.Logger;
3941

42+
import sun.security.util.ByteArrayTagOrder;
43+
4044
/**
4145
* This class is a parser for STL files. Currently, normals specified in the
4246
* file are ignored and recalculated under the assumption that the coordinates
4347
* are provided in right-handed coordinate space (counter-clockwise).
4448
* @author CCHall
49+
* @author Andrew Goh
50+
*
51+
* -reversion: mar 2017 Andrew
52+
* updated logic to handle binary STL files with "solid" in the header
53+
*
4554
*/
4655
public class STLParser {
4756
/**
@@ -55,28 +64,116 @@ public class STLParser {
5564
* @throws IllegalArgumentException Thrown if the STL is not properly
5665
* formatted
5766
*/
58-
public static List<Triangle> parseSTLFile(Path filepath) throws IOException{
67+
public List<Triangle> parseSTLFile(Path filepath)
68+
throws IOException, IllegalArgumentException {
5969
byte[] allBytes = Files.readAllBytes(filepath);
6070
// determine if it is ASCII or binary STL
61-
Charset charset = Charset.forName("UTF-8");
62-
CharBuffer decode = charset.decode(ByteBuffer.wrap(allBytes, 0, 80));
63-
String headerString = decode.toString();
64-
int index = 0;
65-
while(Character.isWhitespace(headerString.charAt(index)) && index < 80){
66-
index++;
71+
72+
//some binary STL files has "solid" in the first 80 chars
73+
//this breaks logic that determines if a file is ascii based on it
74+
//simply beginning with "solid"
75+
boolean isASCIISTL = false;
76+
77+
//read the first 512 chars or less
78+
String buf = readblock(allBytes, 0, 512);
79+
StringBuffer sb = new StringBuffer();
80+
int inl = readline(buf, sb, 0);
81+
String line = sb.toString();
82+
StringTokenizer st = new StringTokenizer(line);
83+
String token = st.nextToken();
84+
if(token.equals("solid")) { //start with "solid"
85+
if(inl>-1) { //found new line for next line
86+
sb = new StringBuffer();
87+
inl = readline(buf, sb, inl+1); //read next line, update inl
88+
line = sb.toString();
89+
st = new StringTokenizer(line);
90+
token = st.nextToken();
91+
if(token.equals("endsolid"))
92+
isASCIISTL = true; //empty ascii file
93+
else if(token.equals("facet")) {
94+
isASCIISTL = true; //ascii file
95+
} else if (isbinaryfile(allBytes))
96+
isASCIISTL = false; //binary file
97+
} else { //no linefeed
98+
if (isbinaryfile(allBytes))
99+
isASCIISTL = false; //binary file
100+
}
101+
} else {//does not starts with "solid"
102+
if (isbinaryfile(allBytes))
103+
isASCIISTL = false; //binary file
67104
}
68-
String firstWord = headerString.substring(index);
69-
boolean isASCIISTL = (firstWord.toLowerCase().startsWith("solid"));
70-
105+
71106
// read file to array of triangles
72107
List<Triangle> mesh;
73108
if(isASCIISTL){
109+
Charset charset = Charset.forName("UTF-8");
74110
mesh = readASCII(charset.decode(ByteBuffer.wrap(allBytes)).toString().toLowerCase());
75111
} else {
76112
mesh = readBinary(allBytes);
77113
}
78114
return mesh;
79115
}
116+
117+
public String readblock(byte[] allBytes, int offset, int length) {
118+
if(allBytes.length-offset<length) length = allBytes.length-offset;
119+
Charset charset = Charset.forName("UTF-8");
120+
CharBuffer decode = charset.decode(ByteBuffer.wrap(allBytes, offset, length));
121+
return decode.toString().toLowerCase();
122+
}
123+
124+
public int readline(String buf, StringBuffer sb, int offset) {
125+
int il = buf.indexOf('\n', offset);
126+
if(il>-1)
127+
sb.append(buf.substring(offset, il-1));
128+
else
129+
sb.append(buf.substring(offset));
130+
return il;
131+
}
132+
133+
public String lastline(String buf) {
134+
int i = buf.length();
135+
while(--i>-1) {
136+
if(buf.charAt(i) == '\n')
137+
break;
138+
}
139+
if (i>-1)
140+
return buf.substring(i+1);
141+
else
142+
return "";
143+
}
144+
145+
public boolean isbinaryfile(byte[] allBytes) throws IllegalArgumentException {
146+
if (allBytes.length<84)
147+
throw new IllegalArgumentException("invalid binary file, length<84");
148+
int numtriangles = byteatoint(Arrays.copyOfRange(allBytes, 80, 84));
149+
if (allBytes.length >= 84 + numtriangles * 50)
150+
return true; //is binary file
151+
else {
152+
String msg = "invalid binary file, num triangles does not match length specs";
153+
throw new IllegalArgumentException(msg);
154+
}
155+
}
156+
157+
// little endian
158+
public int byteatoint(byte[] bytes) {
159+
assert (bytes.length == 4);
160+
int r = 0;
161+
r = bytes[0] & 0xff;
162+
r |= (bytes[1] & 0xff) << 8;
163+
r |= (bytes[2] & 0xff) << 16;
164+
r |= (bytes[3] & 0xff) << 24 ;
165+
return r;
166+
}
167+
168+
public byte[] inttobytea(int value) {
169+
byte bytes[] = new byte[4];
170+
bytes[0] = (byte) value;
171+
bytes[1] = (byte)(value >> 8);
172+
bytes[2] = (byte)(value >> 16);
173+
bytes[3] = (byte)(value >> 24);
174+
return bytes;
175+
}
176+
80177
/**
81178
* Reads an STL ASCII file content provided as a String
82179
* @param content ASCII STL
@@ -85,7 +182,7 @@ public static List<Triangle> parseSTLFile(Path filepath) throws IOException{
85182
* @throws IllegalArgumentException Thrown if the STL is not properly
86183
* formatted
87184
*/
88-
public static List<Triangle> readASCII(String content) throws IllegalArgumentException {
185+
public List<Triangle> readASCII(String content) throws IllegalArgumentException {
89186
Logger.getLogger(STLParser.class.getName()).log(Level.FINEST,"Parsing ASCII STL format");
90187
// string is lowercase
91188
ArrayList<Triangle> triangles = new ArrayList<>();
@@ -149,7 +246,7 @@ public static List<Triangle> readASCII(String content) throws IllegalArgumentExc
149246
* @throws IllegalArgumentException Thrown if the STL is not properly
150247
* formatted
151248
*/
152-
public static List<Triangle> readBinary(byte[] allBytes) throws IllegalArgumentException {
249+
public List<Triangle> readBinary(byte[] allBytes) throws IllegalArgumentException {
153250
Logger.getLogger(STLParser.class.getName()).log(Level.FINEST,"Parsing binary STL format");
154251
DataInputStream in = new DataInputStream(new ByteArrayInputStream(allBytes));
155252
ArrayList<Triangle> triangles = new ArrayList<>();

src/hall/collin/christopher/stl4j/TestApp.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public static void main(String[] arg){
6262
try {
6363

6464
// read file to array of triangles
65-
List<Triangle> mesh = STLParser.parseSTLFile(f.toPath());
65+
List<Triangle> mesh = new STLParser().parseSTLFile(f.toPath());
6666

6767

6868
// show the results

src/org/stlviewer/STLViewer.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
import javax.swing.JMenuItem;
2929
import javax.swing.JToolBar;
3030

31-
import org.stlviewer.PModel;
32-
3331
import com.sun.j3d.utils.universe.SimpleUniverse;
3432
import com.sun.j3d.utils.universe.ViewingPlatform;
3533

@@ -154,7 +152,7 @@ private void loadfile() {
154152
// read file to array of triangles
155153
try {
156154

157-
List<Triangle> mesh = STLParser.parseSTLFile(file.toPath());
155+
List<Triangle> mesh = new STLParser().parseSTLFile(file.toPath());
158156

159157
if (mesh == null || mesh.isEmpty()) {
160158
lstatusline.setText("no data read, possible file error");

stlviewer.jar

-5.72 KB
Binary file not shown.

0 commit comments

Comments
 (0)