用C#怎么读取二进制格式的STL文件里边的数据

.Net技术 码拜 9年前 (2015-07-11) 3173次浏览 0个评论
 

ASCII格式 的没问题。
但是二进制格式的不知道怎么读取。

二进制的数据格式说明如下:

二进制STL文件用固定的字节数来给出三角面片的几何信息。
文件起始的80个字节是文件头,用于存贮文件名;
紧接着用 4 个字节的整数来描述模型的三角面片个数,
后面逐个给出每个三角面片的几何信息。每个三角面片占用固定的50个字节,依次是:
3个4字节浮点数(角面片的法矢量)
3个4字节浮点数(1个顶点的坐标)
3个4字节浮点数(2个顶点的坐标)
3个4字节浮点数(3个顶点的坐标)个
三角面片的最后2个字节用来描述三角面片的属性信息。
一个完整二进制STL文件的大小为三角形面片数乘以 50再加上84个字节。
二进制:
UINT8//Header//文件头
UINT32//Numberoftriangles//三角面片数量
//foreachtriangle(每个三角面片中)
REAL32[3]//Normalvector//法线矢量
REAL32[3]//Vertex1//顶点1坐标
REAL32[3]//Vertex2//顶点2坐标
REAL32[3]//Vertex3//顶点3坐标
UINT16//Attributebytecountend//文件属性统计

我如何读取各顶点坐标?

ASCII格式的我可以通过逐行读取,然后再分析,但二进制格式的打开是乱码,不知道怎么读取。

谢谢。

5分

直接二进制读取,按照你的字段的含义解析成对应的变量
 

比如:UINT32//Numberoftriangles//三角面片数量
这个,应该是从81个字节开始,读取4个字节吧?但读出来的数据有点离谱,对不上。

5分

用ultraedit比较下,另外,x86是big endian的,比如整数513(0x201),存储的是01 02 00 00,而不是00 00 02 01

5分

对于浮点数、整数,一种简单的解析方式是用BitConverter.ToDouble ToInt32等等,传入数组和偏移就可以了。

10分

一边二进制读取,一边打开Hex编辑器 比较数据。

Hex编辑器我一般用Notepad++家Hex 插件。
或者直接用VS打开:
File>>Open>>File
On the open file dialog at the bottom there is a down arrow on the “Open” button
Click “Open WIth”
Click “Binary Editor”
Click OK

注意big endian 和 litter endian.

没有数据很难分析问题在哪里。

 
1、单精度浮点数的转换

var n = BitConverter.GetBytes(1f);

Console.WriteLine(string.Join(",", n));
Console.WriteLine(BitConverter.ToSingle(n, 0));

用C#怎么读取二进制格式的STL文件里边的数据

2、文件偏移是从 0 开始的
UINT32//Numberoftriangles//三角面片数量
应从 80 开始读,而不是 81

 
可以用BinaryReader来读取。

using (BinaryReader reader = new BinaryReader(File.OpenRead("data.stl")))
{
    reader.ReadBytes(80);   // 文件头
    reader.ReadUInt32(); // 三角面片个数
    reader.ReadSingle();  // 读取顶点坐标
}

5分

建议搜索一下STL文件的二进制格式,然后根据二进制根式读取数据
 
http://baike.baidu.com/link url=Et4vCIkMRgcITIJSqNucyjDslIRq8ZQQAaT7Fbj3wN1ZxbcsdCDYMgT9vloGrZct3q2hCkkf0IrrseX0aRjIn_
 
FileStream file = new FileStream(Server.MapPath(“3.stl”), FileMode.Open, FileAccess.Read);
BinaryReader read = new BinaryReader(file);
byte[] head=read.ReadBytes(80);
string str = System.Text.Encoding.Default.GetString(head);
Response.Write(str + “<br>”);//文件头

int facecount=Convert.ToInt32(read.ReadUInt32()); // 三角面片个数
int bytelen = facecount * 50 + 84;
Response.Write(facecount.ToString() + “<br>”);
float v0;
for (int i = 0; i < facecount; i++)
{
for (int j = 0; j < 3; j++)
{
v0 = read.ReadSingle(); //
Response.Write(v0 + “&nbsp;&nbsp;&nbsp;”);
}
Response.Write(“<br>”);
}
、—————————————-用以上代码请取,只正确读到了第一个面的顶点,其它的数据对不上,如图:

用C#怎么读取二进制格式的STL文件里边的数据
用C#怎么读取二进制格式的STL文件里边的数据

哪儿出问题呢?

10分

你漏了 UINT16//Attributebytecountend//文件属性统计 没读
 

加上去了数据还是对不上,似乎不单单是这个原因,暂时还没搞明白。谢谢版主

10分

以下代码没有测试过

    public class STLFile
    {
        public STLFile()
        {
            _triangles = new List<Triangle>();
        }

        public string Name { get; set; }

        private List<Triangle> _triangles;

        public List<Triangle> Triangles
        {
            get { return _triangles; }
        }

        public static STLFile LoadBinary(string path)
        {
            using (BinaryReader reader = new BinaryReader(File.OpenRead(path)))
            {
                byte[] data;
                int count;

                data = reader.ReadBytes(80);
                count = (int)reader.ReadUInt32();

                if (reader.BaseStream.Length != count * 50 + 84)
                    throw new InvalidDataException("STL文件长度无效");

                STLFile file = new STLFile();

                file.Name = Encoding.Default.GetString(data);

                for (int i = 0; i < count; i++)
                {
                    file.Triangles.Add(Triangle.Read(reader));
                }

                return file;
            }
        }
    }

    public struct Coordinate
    {
        public float X;
        public float Y;
        public float Z;

        internal static Coordinate Read(BinaryReader reader)
        {
            Coordinate coor = new Coordinate();
            coor.X = reader.ReadSingle();
            coor.Y = reader.ReadSingle();
            coor.Z = reader.ReadSingle();

            return coor;
        }
    }

    public class Triangle
    {
        public Coordinate NormalVector { get; set; }

        public Coordinate Vertex1 { get; set; }

        public Coordinate Vertex2 { get; set; }

        public Coordinate Vertex3 { get; set; }

        public int Attributes { get; set; }


        internal static Triangle Read(BinaryReader reader)
        {
            Triangle triangle = new Triangle();

            triangle.NormalVector = Coordinate.Read(reader);
            triangle.Vertex1 = Coordinate.Read(reader);
            triangle.Vertex2 = Coordinate.Read(reader);
            triangle.Vertex3 = Coordinate.Read(reader);
            triangle.Attributes = reader.ReadUInt16();

            return triangle;
        }
    }

STLFile.LoadBinary(“xxx.stl”);

10分

1、int facecount = read.ReadUInt32(); // 三角面片个数
2、for (int i = 0; i < facecount; i++)
{
for (int j = 0; j < 3; j++)
{
v0 = read.ReadSingle(); //
Response.Write(v0 + “&nbsp;&nbsp;&nbsp;”);
}
Response.Write(read.ReadUInt16() + “<br>”);
}
 
引用 14 楼 xuzuning 的回复:

1、int facecount = read.ReadUInt32(); // 三角面片个数
2、for (int i = 0; i < facecount; i++)
{
for (int j = 0; j < 3; j++)
{
v0 = read.ReadSingle(); //
Response.Write(v0 + “&nbsp;&nbsp;&nbsp;”);
}
Response.Write(read.ReadUInt16() + “<br>”);
}

谢谢。已经解决了,还漏掉了前面的。
REAL32[3]//Normalvector//法线矢量

感谢各位热心人的支持!

 
做一个延续吧。

如何判断 是以 ASCII 方式存储还是以二进制方式存储
因为要选 择不同的读取方法,所以得先判断是以哪种方式存储。
谢谢。

 
先以十进制方式打开,然后验证文件长度,假如长度不匹配,再试着用文本方式读取。
 
没有更好的方法,除非文件格式存在固有的区别,你才能正确解析,否则肯定有误读情况出现
 
你做了跳字节了吗,写入的时候有没有跳字节,文件最大类型是4字节的,所以按4字节对齐,最前面读文件头,需要跳3个字节才继续读后面的数据
 
求楼主读取ASCII格式的程序,非常感谢

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明用C#怎么读取二进制格式的STL文件里边的数据
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!