Tanoda
pb_Stl.cs
Go to the documentation of this file.
1using System.Text;
2using System.Collections.Generic;
3using System.IO;
4using UnityEngine;
5using System.Linq;
6
7namespace Parabox.STL
8{
12 public enum FileType
13 {
14 Ascii,
15 Binary
16 };
17
21 public static class pb_Stl
22 {
26 public static bool WriteFile(string path, Mesh mesh, FileType type = FileType.Ascii, bool convertToRightHandedCoordinates = true)
27 {
28 return WriteFile(path, new Mesh[] { mesh }, type, convertToRightHandedCoordinates);
29 }
30
41 public static bool WriteFile(string path, IList<Mesh> meshes, FileType type = FileType.Ascii, bool convertToRightHandedCoordinates = true)
42 {
43 try
44 {
45 switch(type)
46 {
47 case FileType.Binary:
48 {
49 // http://paulbourke.net/dataformats/stl/
50 // http://www.fabbers.com/tech/STL_Format
51 using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create), new ASCIIEncoding()))
52 {
53 // 80 byte header
54 writer.Write(new byte[80]);
55
56 uint totalTriangleCount = (uint) (meshes.Sum(x => x.triangles.Length) / 3);
57
58 // unsigned long facet count (4 bytes)
59 writer.Write( totalTriangleCount );
60
61 foreach(Mesh mesh in meshes)
62 {
63 Vector3[] v = convertToRightHandedCoordinates ? Left2Right(mesh.vertices) : mesh.vertices;
64 Vector3[] n = convertToRightHandedCoordinates ? Left2Right(mesh.normals) : mesh.normals;
65 int[] t = mesh.triangles;
66 int triangleCount = t.Length;
67 if(convertToRightHandedCoordinates)
68 System.Array.Reverse(t);
69
70 for(int i = 0; i < triangleCount; i += 3)
71 {
72 int a = t[i], b = t[i+1], c = t[i+2];
73
74 Vector3 avg = AvgNrm(n[a], n[b], n[c]);
75
76 writer.Write(avg.x);
77 writer.Write(avg.y);
78 writer.Write(avg.z);
79
80 writer.Write(v[a].x);
81 writer.Write(v[a].y);
82 writer.Write(v[a].z);
83
84 writer.Write(v[b].x);
85 writer.Write(v[b].y);
86 writer.Write(v[b].z);
87
88 writer.Write(v[c].x);
89 writer.Write(v[c].y);
90 writer.Write(v[c].z);
91
92 // specification says attribute byte count should be set to 0.
93 writer.Write( (ushort)0 );
94 }
95 }
96 }
97 }
98 break;
99
100 default:
101 string model = WriteString(meshes);
102 File.WriteAllText(path, model);
103 break;
104 }
105 }
106 catch(System.Exception e)
107 {
108 UnityEngine.Debug.LogError(e.ToString());
109 return false;
110 }
111
112 return true;
113 }
114
118 public static string WriteString(Mesh mesh, bool convertToRightHandedCoordinates = true)
119 {
120 return WriteString(new Mesh[] { mesh }, convertToRightHandedCoordinates);
121 }
122
126 public static string WriteString(IList<Mesh> meshes, bool convertToRightHandedCoordinates = true)
127 {
128 StringBuilder sb = new StringBuilder();
129
130 string name = meshes.Count == 1 ? meshes[0].name : "Composite Mesh";
131
132 sb.AppendLine(string.Format("solid {0}", name));
133
134 foreach(Mesh mesh in meshes)
135 {
136 Vector3[] v = convertToRightHandedCoordinates ? Left2Right(mesh.vertices) : mesh.vertices;
137 Vector3[] n = convertToRightHandedCoordinates ? Left2Right(mesh.normals) : mesh.normals;
138 int[] t = mesh.triangles;
139 if(convertToRightHandedCoordinates) System.Array.Reverse(t);
140 int triLen = t.Length;
141
142 for(int i = 0; i < triLen; i+=3)
143 {
144 int a = t[i];
145 int b = t[i+1];
146 int c = t[i+2];
147
148 Vector3 nrm = AvgNrm(n[a], n[b], n[c]);
149
150 sb.AppendLine(string.Format("facet normal {0} {1} {2}", nrm.x, nrm.y, nrm.z));
151
152 sb.AppendLine("outer loop");
153
154 sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[a].x, v[a].y, v[a].z));
155 sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[b].x, v[b].y, v[b].z));
156 sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[c].x, v[c].y, v[c].z));
157
158 sb.AppendLine("endloop");
159
160 sb.AppendLine("endfacet");
161 }
162 }
163
164 sb.AppendLine(string.Format("endsolid {0}", name));
165
166 return sb.ToString();
167 }
168
169 private static Vector3[] Left2Right(Vector3[] v)
170 {
171 Matrix4x4 l2r = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, 1f, -1f));
172 Vector3[] r = new Vector3[v.Length];
173
174 for(int i = 0; i < v.Length; i++)
175 r[i] = l2r.MultiplyPoint3x4(v[i]);
176
177 return r;
178 }
179
183 private static Vector3 AvgNrm(Vector3 a, Vector3 b, Vector3 c)
184 {
185 return new Vector3(
186 (a.x + b.x + c.x) / 3f,
187 (a.y + b.y + c.y) / 3f,
188 (a.z + b.z + c.z) / 3f );
189 }
190 }
191}
System.IO.FileMode FileMode
Definition: AssetLoader.cs:14