STL文件
关键词:.stl vtk Qt C++ 解析 读写*
文件简介
*.stl文件是一种用空间三角形面片逼近三维实体的3D模型文件,只能用来表示封闭的面或体。一个完整的STL文件记载了组成实体模型的所有三角形面片的法向量数据和顶点坐标数据信息。
文件规则
共顶点规则
每一个三角面片必须与其相邻的每一个面片共两个顶点 ,即一个三角面片的顶点不能落在相邻的任何三角面片的边上;
取向规则
单个面片法向量符合右手法则且其法向量必须指向实体外面;
充满规则
小三角面片必须布满三维模型的所有表面,不得有任何遗漏;
取值规则
每个顶点的坐标值必须为非负 ,即 *.stl文件的实体应该在坐标系的第一象限.
文件分类
目前的STL文件格式包括二进制文件(BINARY)和文本文件(ASCII)两种.
二进制格式
二进制STL文件用固定的字节数来给出三角面片的几何信息。
UINT8//Header//文件头,存贮文件名,80个字节
UINT32//Numberoftriangles//三角面片数量,4 个字节的整数,小端存储
//(每个三角面片,小端存储)
REAL32[3]//Normalvector//法线矢量,指向立方体的外部,可以通过右手定则恢复顶点顺序,3个4字节浮点数
REAL32[3]//Vertex1//顶点1坐标,3个4字节浮点数
REAL32[3]//Vertex2//顶点2坐标,3个4字节浮点数
REAL32[3]//Vertex3//顶点3坐标,3个4字节浮点数
UINT16//Attributebytecountend//文件属性统计,2个字节
//
STL文件大小 = 80 + 4 + 50 * 三角面片个数
ASCALL 文件格式
ASCII格式的 STL 文件结构如下:
solid name //"solid"标识+上文件名,文件名可以是任意字符
facet normal ni nj nk //“facetnormal”标识+法线数据i,j,k
outer loop //“outorloop”标识
vertex x1 y1 z1 //“vertex”标识+第一个顶点数据x,y,z
vertex x2 y2 z2 //第二个顶点
vertex x3 y3 z3 //第三个顶点
endloop //“endloop”标识
endfacet //"endfacet"标识
//更多三角面···
endsolid name //文件末尾,“endsolid”标识+文件名
文件读写
使用VTK读取和写入
#include <vtkSTLReader.h>
auto reader = vtkSmartPointer<vtkSTLReader>::New();
reader->SetFileName("文件路径");
reader->Update();
#include <vtkSTLWriter.h>
auto stlWriter = vtkSmartPointer<vtkSTLWriter>::New();
stlWriter->SetFileName(".//data\\bone.stl");
stlWriter->SetInputConnection(marchingcube->GetOutputPort());
C++ 解析STL
#pragma once
#include<vector>
class Point3f;
class analysis
{
public:
analysis();
~analysis();
public:
bool ReadFile(const char *cfilename);
int NumTri();
std::vector<Point3f>& PointList();
private:
std::vector<Point3f> pointList;
unsigned int unTriangles;
bool ReadASCII(const char *cfilename);
bool ReadBinary(const char *cfilename);
char* memwriter;
int cpyint(const char*& p);
float cpyfloat(const char*& p);
};
#pragma once
#include <vector>
#include <fstream>
#include"Point3f.h"
#include <iostream>
#include <string>
#include"analysis.h"
#include <sstream>
using namespace std;
analysis::analysis()
{
}
analysis::~analysis()
{
}
bool analysis::ReadFile(const char *cfilename)
{
FILE * pFile;
long lSize;
char* buffer;
size_t result;
/* 若要一个byte不漏地读入整个文件,只能采用二进制方式打开 */
fopen_s(&pFile, cfilename, "rb");
if (pFile == NULL)
{
fputs("File error", stderr);
exit(1);
}
/* 获取文件大小 */
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
rewind(pFile);
/* 分配内存存储整个文件 */
buffer = (char*)malloc(sizeof(char)*lSize);
if (buffer == NULL)
{
fputs("Memory error", stderr);
exit(2);
}
/* 将文件拷贝到buffer中 */
result = fread(buffer, 1, lSize, pFile);
if (result != lSize)
{
fputs("Reading error", stderr);
exit(3);
}
/* 结束演示,关闭文件并释放内存 */
fclose(pFile);
ios::sync_with_stdio(false);
if (buffer[79] != '\0')//判断格式
{
ReadASCII(buffer);
}
else
{
ReadBinary(buffer);
}
ios::sync_with_stdio(true);
free(buffer);
return true;
}
bool analysis::ReadASCII(const char *buffer)
{
unTriangles = 0;
float x, y, z;
int i;
string name, useless;
stringstream ss(buffer);
getline(ss, name);
ss.get();
do {
ss >> useless;
if (useless != "facet")
break;
getline(ss, useless);
getline(ss, useless);
for (i = 0; i < 3; i++)
{
ss >> useless >> x >> y >> z;
pointList.push_back(Point3f(x, y, z));
}
unTriangles++;
getline(ss, useless);
getline(ss, useless);
getline(ss, useless);
} while (1);
return true;
}
bool analysis::ReadBinary(const char *buffer)
{
const char* p = buffer;
char name[80];
int i, j;
memcpy(name, p, 80);
p += 80;
unTriangles = cpyint(p);
for (i = 0; i < unTriangles; i++)
{
p += 12;//跳过头部法向量
for (j = 0; j < 3; j++)//读取三顶点
pointList.push_back(Point3f(cpyfloat(p), cpyfloat(p), cpyfloat(p)));
p += 2;//跳过尾部标志
}
return true;
}
int analysis::NumTri()
{
return unTriangles;
}
std::vector<Point3f>& analysis::PointList()
{
return pointList;
}
int analysis::cpyint(const char*& p)
{
int cpy;
memwriter = (char*)&cpy;
memcpy(memwriter, p, 4);
p += 4;
return cpy;
}
float analysis::cpyfloat(const char*& p)
{
float cpy;
memwriter = (char*)&cpy;
memcpy(memwriter, p, 4);
p += 4;
return cpy;
}
#pragma once
#include<windows.h>
//-----------------------------顶点结构体----------------------------------
struct Vertex //顶点结构
{
Vertex() {}
Vertex(float x, float y, float z)
{
_x = x; _y = y; _z = z;
}
float _x, _y, _z;
static const DWORD FVF;
};
class Point3f
{
public:
Point3f();
Point3f(float _x, float _y, float _z);
int SetParam(float _x, float _y, float _z);
inline Vertex IVertex()
{
return Vertex(x, y, z);
}
private:
float x, y, z;
};
#pragma once
#include"Point3f.h"
Point3f::Point3f() :x(0), y(0), z(0)
{
}
Point3f::Point3f(float _x, float _y, float _z) : x(_x), y(_y), z(_z)
{
}
int Point3f::SetParam(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
return 0;
}