java stl分解_stl文件格式解析代码--java版
packagetest_stl.test_entry;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/*** 注意java byte范围-128~127
*
*@authorephuizi@gmail.com
**/
public classSTLUtils {//final private static Pattern ASCII_PATTERN_FACET =//Pattern.compile("facet([\\s\\S]*?)endfacet");
final private static Pattern ASCII_PATTERN_NORMAL =Pattern
.compile("normal[\\s]+([\\-+]?[0-9]+\\.?[0-9]*([eE][\\-+]?[0-9]+)?)+[\\s]+([\\-+]?[0-9]*\\.?[0-9]+([eE][\\-+]?[0-9]+)?)+[\\s]+([\\-+]?[0-9]*\\.?[0-9]+([eE][\\-+]?[0-9]+)?)+");final private static Pattern ASCII_PATTERN_VERTEX =Pattern
.compile("vertex[\\s]+([\\-+]?[0-9]+\\.?[0-9]*([eE][\\-+]?[0-9]+)?)+[\\s]+([\\-+]?[0-9]*\\.?[0-9]+([eE][\\-+]?[0-9]+)?)+[\\s]+([\\-+]?[0-9]*\\.?[0-9]+([eE][\\-+]?[0-9]+)?)+");/*** 判断是否stl格式
*
*@paramstlPath
*@returntrue binary false ascii*/
public static booleanisBinary(String stlPath) {long expect = 0;//以binnary方式计算的文件大小;
int face_size = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8);//一个三角片大小
int n_facetNum = 0;//三角片数量
RandomAccessFile stl = null;try{
stl= new RandomAccessFile(stlPath, "r");
stl.seek(80);byte[] arr = { 0, 0, 0, 0};
stl.read(arr);
n_facetNum=STLFaceNum(arr);
expect= 80 + (32 / 8) + (n_facetNum *face_size);if (expect ==stl.length()) {
stl.close();return true;
}//some binary files will have different size from expected,//checking characters lower than ASCII to confirm is binary
long fileLength =stl.length();
stl.seek(0);for (long index = 0; index < fileLength; index++) {if (stl.readByte() < 0) {
stl.close();return true;
}
}
stl.close();return false;
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}return false;
}/*** 用于正数,因为负数存储是补码 第81~84四个字节
*
*@paramarr
*@return
*/
public static int STLFaceNum(byte[] arr) {if (arr != null && arr.length == 4) {int a = arr[0] & (0xFF);//防止低位转二进制后是变成负数
int b = (arr[1] << 8) & (0xFFFF);int c = (arr[2] << 16) & (0xFFFFFF);int d = (arr[3] << 24) & (0xFFFFFFFF);return a + b + c +d;
}return -1;
}/*** resolve binary stl file
*
*@paramstlPath
*@return
*/
public staticSTLFile parseBinary(String stlPath) {
RandomAccessFile stl= null;try{
stl= new RandomAccessFile(stlPath, "r");
stl.seek(80);byte[] arr = { 0, 0, 0, 0};
stl.read(arr);int facetNum =STLFaceNum(arr);float r = 0, g = 0, b = 0;boolean hasColors = false;float[] colors = null;float defaultR = 0, defaultG = 0, defaultB = 0, alpha = 0;//process STL header//check for default color in header ("COLOR=rgba" sequence).
for (int index = 0; index < 80 - 10; index++) {
stl.seek(index);//6字节("COLOR=")
if (stl.readInt() == 0x434F4C4F /*COLO*/&& (stl.readByte() == 0x52 /*'R'*/)&& (stl.readByte() == 0x3D /*'='*/)) {
hasColors= true;
colors= new float[facetNum * 3 * 3];//一个面三个点每个点(r,b,g)
defaultR= STLUtils.toFloat(stl.readByte()) / 255;//6
defaultG = STLUtils.toFloat(stl.readByte()) / 255;//7
defaultB = STLUtils.toFloat(stl.readByte()) / 255;//8
alpha = STLUtils.toFloat(stl.readByte()) / 255;//9
break;
}
}int dataOffset = 84;int offset = 0;float[] vertices = new float[facetNum * 3 * 3];float[] normals = new float[facetNum * 3 * 3];//三角面片法向量的3个分量值数据
byte temp[] = { 0, 0, 0, 0};int max = 0;//第一个三角片z轴高度
boolean isBegin = true;
stl.seek(dataOffset);for (int face = 0; face < facetNum; face++) {//法向量12个字节
stl.read(temp);float normalX = STLUtils.toFloat(temp);//4
stl.read(temp);float normalY = STLUtils.toFloat(temp);//4
stl.read(temp);float normalZ = STLUtils.toFloat(temp);//4//顶点坐标36字节
for (int i = 1; i <= 3; i++) {
stl.read(temp);
vertices[offset]=STLUtils.toFloat(temp);
stl.read(temp);
vertices[offset+ 1] =STLUtils.toFloat(temp);
stl.read(temp);
vertices[offset+ 2] =STLUtils.toFloat(temp);if(isBegin) {
isBegin= false;
max= (int) (vertices[offset + 2]);
}
normals[offset]=normalX;
normals[offset+ 1] =normalY;
normals[offset+ 2] =normalZ;
offset+= 3;//增加位移
}//color2字节
if(hasColors) {int packedColor = STLUtils.toInt(stl.readByte()) | STLUtils.toInt(stl.readByte()) << 8 & 0xFFFF;if ((packedColor & 0x8000) == 0) { //facet has its own//unique color
r= (packedColor & 0x1F) / 31;
g= ((packedColor >> 5) & 0x1F) / 31;
b= ((packedColor >> 10) & 0x1F) / 31;
}else{
r=defaultR;
g=defaultG;
b=defaultB;
}
}else{//无颜色 丢弃2字节
stl.readByte();
stl.readByte();
}//补充颜色
if(hasColors) {
colors[face* 9 + 0] =r;
colors[face* 9 + 1] =g;
colors[face* 9 + 2] =b;
colors[face* 9 + 3] =r;
colors[face* 9 + 4] =g;
colors[face* 9 + 5] =b;
colors[face* 9 + 6] =r;
colors[face* 9 + 7] =g;
colors[face* 9 + 8] =b;
}
}
stl.close();return newSTLFile(max, facetNum, alpha, hasColors, vertices, normals, colors);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}return null;
}public staticSTLFile parseASCII(String stlPath) {int facetNum =asciiFacetNum(stlPath);
RandomAccessFile stl= null;try{
stl= new RandomAccessFile(stlPath, "r");float[] vertices = new float[facetNum * 3 * 3];float[] normals = new float[facetNum * 3 * 3];//三角面片法向量的3个分量值数据
final String FACET_END = "endfacet";
StringBuffer bf= new StringBuffer();//record one-facet
int facetIndex = 0;
String line= null;while ((line = stl.readLine()) != null) {
bf.append(line);if (line.length() > 8 && line.length() < 15 &&line.contains(FACET_END)) {//one facet
String oneFacet =bf.toString();
Matcher nMatcher=ASCII_PATTERN_NORMAL.matcher(oneFacet);if (!nMatcher.find())continue;
String normal=nMatcher.group();
Matcher mV=ASCII_PATTERN_VERTEX.matcher(oneFacet);if (!mV.find())continue;
String v1= mV.group();//第一个顶点
if (!mV.find())continue;
String v2= mV.group();//第二个顶点
if (!mV.find())continue;
String v3= mV.group();//第三个顶点//解析法向量
String GAP = " ";int nfIndex = facetIndex * 9;
String[] n_f_arr=normal.split(GAP);
normals[nfIndex+ 6] = normals[nfIndex + 3] = normals[nfIndex] = Float.parseFloat(n_f_arr[1]);
normals[nfIndex+ 1 + 6] = normals[nfIndex + 1 + 3] = normals[nfIndex + 1] =Float
.parseFloat(n_f_arr[2]);
normals[nfIndex+ 2 + 6] = normals[nfIndex + 2 + 3] = normals[nfIndex + 2] =Float
.parseFloat(n_f_arr[3]);//解析顶点
String[] v1_f_arr =v1.split(GAP);
vertices[nfIndex+ 0] = Float.parseFloat(v1_f_arr[1]);//x
vertices[nfIndex + 1] = Float.parseFloat(v1_f_arr[2]);//y
vertices[nfIndex + 2] = Float.parseFloat(v1_f_arr[3]);//z
String[] v2_f_arr=v2.split(GAP);
vertices[nfIndex+ 3] = Float.parseFloat(v2_f_arr[1]);
vertices[nfIndex+ 4] = Float.parseFloat(v2_f_arr[2]);
vertices[nfIndex+ 5] = Float.parseFloat(v2_f_arr[3]);
String[] v3_f_arr=v3.split(GAP);
vertices[nfIndex+ 6] = Float.parseFloat(v3_f_arr[1]);
vertices[nfIndex+ 7] = Float.parseFloat(v3_f_arr[2]);
vertices[nfIndex+ 8] = Float.parseFloat(v3_f_arr[3]);//set bf count=0
facetIndex++;
bf.setLength(0);
}
}
stl.close();int max = (int) vertices[2];return new STLFile(max, facetNum, 0, false, vertices, normals, null);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}return null;
}/*** 计算ascii-stl-file三角片数量
*
*@paramstlPath
*@return
*/
public static final intasciiFacetNum(String stlPath) {
RandomAccessFile stl= null;int facetNum = 0;try{
stl= new RandomAccessFile(stlPath, "r");int lineNum = 0;int c = 0;while (c != -1) {switch (c =stl.read()) {case -1:case '\n':
lineNum++;break;case '\r':
stl.read();//to skip '\n'
lineNum++;break;default:break;
}
}
facetNum= lineNum / 7;
stl.close();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}returnfacetNum;
}/*** -1 原码1000,0001 反码1111,1110 补码1111,1111 所以无符号值 255
*
*@paramb
*@return
*/
public static int toInt(byteb) {return (int) (b & 0xFF);
}/*** -1 原码1000,0001 反码1111,1110 补码1111,1111 所以无符号值 255 带符号位
*
*@paramb
*@return
*/
public static float toFloat(byteb) {return (float) (b & 0xFF);
}/*** 字节转换为浮点
*
*@paramb
* 字节(至少4个字节)
*@paramindex
* 开始位置
*@return
*/
public static float toFloat(byte[] b) {intl;
l= b[0];
l&= 0xff;
l|= ((int) b[1] << 8);
l&= 0xffff;
l|= ((int) b[2] << 16);
l&= 0xffffff;
l|= ((int) b[3] << 24);returnFloat.intBitsToFloat(l);
}/*** 浮点转换为字节
*
*@paramf
*@return
*/
public static byte[] toByteArr(floatf) {//把float转换为byte[]
int fbit =Float.floatToIntBits(f);byte[] b = new byte[4];for (int i = 0; i < 4; i++) {
b[i]= (byte) (fbit >> (24 - i * 8));
}//翻转数组
int len =b.length;//建立一个与源数组元素类型相同的数组
byte[] dest = new byte[len];//为了防止修改源数组,将源数组拷贝一份副本
System.arraycopy(b, 0, dest, 0, len);bytetemp;//将顺位第i个与倒数第i个交换
for (int i = 0; i < len / 2; ++i) {
temp=dest[i];
dest[i]= dest[len - i - 1];
dest[len- i - 1] =temp;
}returndest;
}public static voidmain(String args[]) {
String path= "F:\\three.js-master\\examples\\models\\stl\\ascii\\pr2_head_pan.stl";//ascii
path = "F:\\three.js-master\\examples\\models\\stl\\binary\\pr2_head_pan.stl";//
//binary
path = "F:\\three.js-master\\examples\\models\\stl\\binary\\colored.stl";//
//binary-with-color//path = "D:\\用户目录\\下载\\4s-keychain-keychain-kickstand-hHkUg.stl";
if(STLUtils.isBinary(path)) {
System.out.println(true);
STLUtils.parseBinary(path);
}else{
STLUtils.parseASCII(path);
}
}
}
java stl分解_stl文件格式解析代码--java版相关推荐
- java stl分解_[STL训练]寻梦-题解(Java代码)极简思路
注意事项: insert()方法只能被 StringBuffer 类的对象调用 参考代码: import java.util.Scanner; public class Main { private ...
- java stl分解_Java Thread 之間 記憶體空間分析
Java Thread 之間 記憶體空間分析 SimpleThread.java import com.abc.ChirpControllerDevice; public class SimpleTh ...
- java自带的xml解析,使用Java自带SAX工具解析XML
studentInfo.xml 崔卫兵 PC学院 62354666 男,1982年生,硕士,现就读于北京邮电大学 cwb PC学院 62358888 男,1987年生,硕士,现就读于中国农业大学 xx ...
- java 装配模式_java23种设计模式代码 Java装配模式
一 模板设计模式在多个子类中 , 存在一个共同的方法 , 这个方法拥有相同的执行步骤 . 为了提高代码的复用性 , 将这个相同步骤的方法抽象到父类中 , 形成模板方 法为了让子类能够控制父类中模板方. ...
- eclipse 停止java程序运行_Eclipse:停止运行代码(java)
有时,我会运行一个偶然包含无限循环之类的程序. Eclipse让我继续编辑程序,但速度非常慢. 我该如何阻止它? (我是否想重新启动JVM?)重新启动eclipse本身总是可行的,但这会中断我的工作流 ...
- java连连看两个拐点消除代码,java连连看代码 图片模式,不要百度上那个
图片模式,不要百度上那个数字的爱情就如一杯牛奶咖啡,香香地飘在外面,甜甜地浮在表面,酸酸地含在里面,苦苦地沉在底面,模模糊糊地把你倒映在咖啡里面. import javax.swing.*; impo ...
- java jsoup 网络爬虫 jsoup解析html Java爬虫 Jsoup爬虫 jsoup例子
java jsoup 网络爬虫 java jsoup 网络爬虫 学习例子(一)抓取豆瓣电影名称+推荐星级 java jsoup 网络爬虫 学习例子(二)只抓取豆瓣电影5星(力荐)电影名称 java j ...
- java 以管理员执行cmd_cmd管理员代码 JAVA 管理员权限运行CMD文件
敲什么命令可以以管理员身份启动cmd 我建了一个.bat文件,想启动mysql服务,但是必须是以管理员身份去启动才代码如下: @echo off>nul 2>&1 "%S ...
- java 解析日期格式_日期/时间格式/解析,Java 8样式
java 解析日期格式 自Java 几乎 开始以来,Java开发人员就通过java.util.Date类(自JDK 1.0起)和java.util.Calendar类(自JDK 1.1起 )来处理日期 ...
- 日期/时间格式/解析,Java 8样式
自Java 几乎 开始以来,Java开发人员就通过java.util.Date类(自JDK 1.0起)和java.util.Calendar类(自JDK 1.1起 )来处理日期和时间. 在这段时间内, ...
最新文章
- opengl glad.h和 glu.h
- AGC023D - Go Home
- 【华为云技术分享】开发团队中的任务没人领取,你头疼吗?
- SpringBoot集成gRPC微服务工程搭建实践
- Linux访问windows共享文件夹
- Why hash maps in Java 8 use binary tree instead of linked list?
- Directx游戏中嵌入IE浏览器实现过程
- 创意字体设计,创意思路哪里找
- Android10手机OTG按钮,我又来了-荣耀10青春版手机OTG功能你会用吗?
- (银行案例)智能营销赋能大零售转型
- 七成知识分子走在过劳死边缘
- 一剑走江湖---武汉
- 纺织企业举步维艰,小微纺织企业该如何做?
- matlab怎么多重积分,多重积分的MATLAB实现
- 有关likely和unlikely
- python如何赋值给元组_【Python 1-9】Python手把手教程之——元组和元组的使用技巧...
- 苹果id被锁定恢复方法(appleid被锁定怎么解除)
- 广州大学2020操作系统实验二:银行家算法
- 英语不好影响考PMP吗?
- zynq+ad9361 petalinux使用官方IIO示波器调试记录