File: stl.cpp

package info (click to toggle)
openctm 1.0.3%2Bdfsg1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,704 kB
  • sloc: ansic: 9,241; cpp: 5,199; python: 735; makefile: 29
file content (238 lines) | stat: -rw-r--r-- 6,892 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//-----------------------------------------------------------------------------
// Product:     OpenCTM tools
// File:        stl.cpp
// Description: Implementation of the STL file format importer/exporter.
//-----------------------------------------------------------------------------
// Copyright (c) 2009-2010 Marcus Geelnard
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//     1. The origin of this software must not be misrepresented; you must not
//     claim that you wrote the original software. If you use this software
//     in a product, an acknowledgment in the product documentation would be
//     appreciated but is not required.
//
//     2. Altered source versions must be plainly marked as such, and must not
//     be misrepresented as being the original software.
//
//     3. This notice may not be removed or altered from any source
//     distribution.
//-----------------------------------------------------------------------------

#include <stdexcept>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include "stl.h"

#ifdef _MSC_VER
typedef unsigned int uint32;
#else
#include <stdint.h>
typedef uint32_t uint32;
#endif

using namespace std;


/// Read a 32-bit integer, endian independent.
static uint32 ReadInt32(istream &aStream)
{
  unsigned char buf[4];
  aStream.read((char *) buf, 4);
  return ((uint32) buf[0]) | (((uint32) buf[1]) << 8) |
         (((uint32) buf[2]) << 16) | (((uint32) buf[3]) << 24);
}

/// Write a 32-bit integer, endian independent.
static void WriteInt32(ostream &aStream, uint32 aValue)
{
  unsigned char buf[4];
  buf[0] = aValue & 255;
  buf[1] = (aValue >> 8) & 255;
  buf[2] = (aValue >> 16) & 255;
  buf[3] = (aValue >> 24) & 255;
  aStream.write((char *) buf, 4);
}

/// Read a Vector3, endian independent.
static Vector3 ReadVector3(istream &aStream)
{
  union {
    uint32 i;
    float  f;
  } val;
  Vector3 result;
  val.i = ReadInt32(aStream);
  result.x = val.f;
  val.i = ReadInt32(aStream);
  result.y = val.f;
  val.i = ReadInt32(aStream);
  result.z = val.f;
  return result;
}

/// Write a Vector3, endian independent.
static void WriteVector3(ostream &aStream, Vector3 aValue)
{
  union {
    uint32 i;
    float  f;
  } val;
  val.f = aValue.x;
  WriteInt32(aStream, val.i);
  val.f = aValue.y;
  WriteInt32(aStream, val.i);
  val.f = aValue.z;
  WriteInt32(aStream, val.i);
}

/// Vertex class used when reading and joining the triangle vertices.
class SortVertex {
  public:
    float x, y, z;
    uint32 mOldIndex;

    bool operator<(const SortVertex &v) const
    {
      return (x < v.x) || ((x == v.x) && ((y < v.y) || ((y == v.y) && (z < v.z))));
    }
};

/// Import an STL file from a file.
void Import_STL(const char * aFileName, Mesh * aMesh)
{
  // Clear the mesh
  aMesh->Clear();

  // Open the input file
  ifstream f(aFileName, ios_base::in | ios_base::binary);
  if(f.fail())
    throw runtime_error("Could not open input file.");

  // Get the file size
  f.seekg(0, ios_base::end);
  uint32 fileSize = (uint32) f.tellg();
  f.seekg(0, ios_base::beg);
  if(fileSize < 84)
    throw runtime_error("Invalid format - not a valid STL file.");

  // Read header (80 character comment + triangle count)
  char comment[81];
  f.read(comment, 80);
  comment[80] = 0;
  aMesh->mComment = string(comment);
  uint32 triangleCount = ReadInt32(f);
  if(fileSize != (84 + triangleCount * 50))
    throw runtime_error("Invalid format - not a valid STL file.");

  if(triangleCount > 0)
  {
    // Read all the triangle data
    vector<SortVertex> vertices;
    vertices.resize(triangleCount * 3);
    for(uint32 i = 0; i < triangleCount; ++ i)
    {
      // Skip the flat normal
      f.seekg(12, ios_base::cur);

      // Read the three triangle vertices
      for(uint32 j = 0; j < 3; ++ j)
      {
        Vector3 v = ReadVector3(f);
        uint32 index = i * 3 + j;
        vertices[index].x = v.x;
        vertices[index].y = v.y;
        vertices[index].z = v.z;
        vertices[index].mOldIndex = index;
      }

      // Ignore the two fill bytes
      f.seekg(2, ios_base::cur);
    }

    // Make sure that no redundant copies of vertices exist (STL files are full
    // of vertex duplicates, so remove the redundancy), and store the data in
    // the mesh object
    sort(vertices.begin(), vertices.end());
    aMesh->mVertices.resize(vertices.size());
    aMesh->mIndices.resize(vertices.size());
    SortVertex * firstEqual = &vertices[0];
    int vertIdx = -1;
    for(uint32 i = 0; i < vertices.size(); ++ i)
    {
      if((i == 0) ||
         (vertices[i].z != firstEqual->z) ||
         (vertices[i].y != firstEqual->y) ||
         (vertices[i].x != firstEqual->x))
      {
        firstEqual = &vertices[i];
        ++ vertIdx;
        aMesh->mVertices[vertIdx] = Vector3(firstEqual->x, firstEqual->y, firstEqual->z);
      }
      aMesh->mIndices[vertices[i].mOldIndex] = vertIdx;
    }
    aMesh->mVertices.resize(vertIdx + 1);
  }

  // Close the input file
  f.close();
}

/// Export an STL file to a file.
void Export_STL(const char * aFileName, Mesh * aMesh, Options &aOptions)
{
  // Open the output file
  ofstream f(aFileName, ios_base::out | ios_base::binary);
  if(f.fail())
    throw runtime_error("Could not open output file.");

  // Write header (80-character comment + triangle count)
  char comment[80];
  for(uint32 i = 0; i < 80; ++ i)
  {
    if(i < aMesh->mComment.size())
      comment[i] = aMesh->mComment[i];
    else
      comment[i] = 0;
  }
  f.write(comment, 80);
  uint32 triangleCount = aMesh->mIndices.size() / 3;
  WriteInt32(f, triangleCount);

  // Write the triangle data
  for(uint32 i = 0; i < triangleCount; ++ i)
  {
    // Get the triangle vertices
    Vector3 v1 = aMesh->mVertices[aMesh->mIndices[i * 3]];
    Vector3 v2 = aMesh->mVertices[aMesh->mIndices[i * 3 + 1]];
    Vector3 v3 = aMesh->mVertices[aMesh->mIndices[i * 3 + 2]];

    // Calculate the triangle normal
    Vector3 n1 = v2 - v1;
    Vector3 n2 = v3 - v1;
    Vector3 n = Normalize(Cross(n1, n2));

    // Write the triangle normal
    WriteVector3(f, n);

    // Coordinates
    WriteVector3(f, v1);
    WriteVector3(f, v2);
    WriteVector3(f, v3);

    // Set the two fill bytes to zero
    f.put(0);
    f.put(0);
  }

  // Close the output file
  f.close();
}