1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkSTLWriter.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkSTLWriter.h"
16
17 #include "vtkByteSwap.h"
18 #include "vtkCellArray.h"
19 #include "vtkErrorCode.h"
20 #include "vtkInformation.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkPolyData.h"
23 #include "vtkTriangle.h"
24 #include <vtksys/SystemTools.hxx>
25
26 #if !defined(_WIN32) || defined(__CYGWIN__)
27 # include <unistd.h> /* unlink */
28 #else
29 # include <io.h> /* unlink */
30 #endif
31
32 vtkStandardNewMacro(vtkSTLWriter);
33
34 static char header[]="Visualization Toolkit generated SLA File ";
35
vtkSTLWriter()36 vtkSTLWriter::vtkSTLWriter()
37 {
38 this->FileType = VTK_ASCII;
39 this->FileName = NULL;
40 this->Header = new char[257];
41 strcpy(this->Header, header);
42 }
43
WriteData()44 void vtkSTLWriter::WriteData()
45 {
46 vtkPoints *pts;
47 vtkCellArray *polys;
48 vtkPolyData *input = this->GetInput();
49
50 polys = input->GetPolys();
51 pts = input->GetPoints();
52 if (pts == NULL || polys == NULL )
53 {
54 vtkErrorMacro(<<"No data to write!");
55 return;
56 }
57
58 if ( this->FileName == NULL)
59 {
60 vtkErrorMacro(<< "Please specify FileName to write");
61 this->SetErrorCode(vtkErrorCode::NoFileNameError);
62 return;
63 }
64
65 if ( this->FileType == VTK_BINARY )
66 {
67 this->WriteBinarySTL(pts,polys);
68 if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
69 {
70 vtkErrorMacro("Ran out of disk space; deleting file: "
71 << this->FileName);
72 unlink(this->FileName);
73 }
74 }
75 else
76 {
77 this->WriteAsciiSTL(pts,polys);
78 if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
79 {
80 vtkErrorMacro("Ran out of disk space; deleting file: "
81 << this->FileName);
82 unlink(this->FileName);
83 }
84 }
85 }
86
WriteAsciiSTL(vtkPoints * pts,vtkCellArray * polys)87 void vtkSTLWriter::WriteAsciiSTL(vtkPoints *pts, vtkCellArray *polys)
88 {
89 FILE *fp;
90 double n[3], v1[3], v2[3], v3[3];
91 vtkIdType npts = 0;
92 vtkIdType *indx = 0;
93
94 if ((fp = fopen(this->FileName, "w")) == NULL)
95 {
96 vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
97 this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
98 return;
99 }
100 //
101 // Write header
102 //
103 vtkDebugMacro("Writing ASCII sla file");
104 if (fprintf (fp, "solid ascii\n") < 0)
105 {
106 fclose(fp);
107 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
108 return;
109 }
110 //
111 // Write out triangle polygons. In not a triangle polygon, only first
112 // three vertices are written.
113 //
114 for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
115 {
116 if (npts > 3)
117 {
118 fclose(fp);
119 vtkErrorMacro(<<"STL file only supports triangles");
120 this->SetErrorCode(vtkErrorCode::FileFormatError);
121 return;
122 }
123
124 pts->GetPoint(indx[0],v1);
125 pts->GetPoint(indx[1],v2);
126 pts->GetPoint(indx[2],v3);
127
128 vtkTriangle::ComputeNormal(pts, npts, indx, n);
129
130 if (fprintf (fp, " facet normal %.6g %.6g %.6g\n outer loop\n",
131 n[0], n[1], n[2]) < 0)
132 {
133 fclose(fp);
134 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
135 return;
136 }
137
138 if (fprintf (fp, " vertex %.6g %.6g %.6g\n", v1[0], v1[1], v1[2]) < 0)
139 {
140 fclose(fp);
141 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
142 return;
143 }
144 if (fprintf (fp, " vertex %.6g %.6g %.6g\n", v2[0], v2[1], v2[2]) < 0)
145 {
146 fclose(fp);
147 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
148 return;
149 }
150 if (fprintf (fp, " vertex %.6g %.6g %.6g\n", v3[0], v3[1], v3[2]) < 0)
151 {
152 fclose(fp);
153 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
154 return;
155 }
156
157 if (fprintf (fp, " endloop\n endfacet\n") < 0)
158 {
159 fclose(fp);
160 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
161 return;
162 }
163 }
164 if (fprintf (fp, "endsolid\n") < 0)
165 {
166 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
167 }
168 fclose (fp);
169 }
170
WriteBinarySTL(vtkPoints * pts,vtkCellArray * polys)171 void vtkSTLWriter::WriteBinarySTL(vtkPoints *pts, vtkCellArray *polys)
172 {
173 FILE *fp;
174 double dn[3], v1[3], v2[3], v3[3];
175 vtkIdType npts = 0;
176 vtkIdType *indx = 0;
177 unsigned long ulint;
178 unsigned short ibuff2=0;
179
180 if ((fp = fopen(this->FileName, "wb")) == NULL)
181 {
182 vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
183 this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
184 return;
185 }
186
187 // Write header
188 //
189 vtkDebugMacro("Writing Binary STL file");
190
191 char szHeader[80+1];
192
193 // Check for STL ASCII format key word 'solid'. According to STL file format
194 // only ASCII files can have 'solid' as start key word, so we ignore it and
195 // use VTK string instead.
196 if (vtksys::SystemTools::StringStartsWith(this->Header, "solid"))
197 {
198 vtkDebugMacro("Invalid header for Binary STL file");
199 strcpy(szHeader, header);
200 }
201 else
202 {
203 memset(szHeader, 32, 80); // fill with space (ASCII=>32)
204 sprintf(szHeader, "%s", this->Header);
205 }
206
207 if (fwrite (szHeader, 1, 80, fp) < 80)
208 {
209 fclose(fp);
210 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
211 return;
212 }
213
214 ulint = (unsigned long int) polys->GetNumberOfCells();
215 vtkByteSwap::Swap4LE(&ulint);
216 if (fwrite (&ulint, 1, 4, fp) < 4)
217 {
218 fclose(fp);
219 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
220 return;
221 }
222
223 // Write out triangle polygons. In not a triangle polygon, only first
224 // three vertices are written.
225 //
226 for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
227 {
228 if (npts > 3)
229 {
230 fclose(fp);
231 vtkErrorMacro(<<"STL file only supports triangles");
232 this->SetErrorCode(vtkErrorCode::FileFormatError);
233 return;
234 }
235
236 pts->GetPoint(indx[0],v1);
237 pts->GetPoint(indx[1],v2);
238 pts->GetPoint(indx[2],v3);
239
240 vtkTriangle::ComputeNormal(pts, npts, indx, dn);
241 float n[3];
242 n[0] = (float)dn[0];
243 n[1] = (float)dn[1];
244 n[2] = (float)dn[2];
245 vtkByteSwap::Swap4LE(n);
246 vtkByteSwap::Swap4LE(n+1);
247 vtkByteSwap::Swap4LE(n+2);
248 if (fwrite (n, 4, 3, fp) < 3)
249 {
250 fclose(fp);
251 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
252 return;
253 }
254
255 n[0] = (float)v1[0]; n[1] = (float)v1[1]; n[2] = (float)v1[2];
256 vtkByteSwap::Swap4LE(n);
257 vtkByteSwap::Swap4LE(n+1);
258 vtkByteSwap::Swap4LE(n+2);
259 if (fwrite (n, 4, 3, fp) < 3)
260 {
261 fclose(fp);
262 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
263 return;
264 }
265
266 n[0] = (float)v2[0]; n[1] = (float)v2[1]; n[2] = (float)v2[2];
267 vtkByteSwap::Swap4LE(n);
268 vtkByteSwap::Swap4LE(n+1);
269 vtkByteSwap::Swap4LE(n+2);
270 if (fwrite (n, 4, 3, fp) < 3)
271 {
272 fclose(fp);
273 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
274 return;
275 }
276
277 n[0] = (float)v3[0]; n[1] = (float)v3[1]; n[2] = (float)v3[2];
278 vtkByteSwap::Swap4LE(n);
279 vtkByteSwap::Swap4LE(n+1);
280 vtkByteSwap::Swap4LE(n+2);
281 if (fwrite (n, 4, 3, fp) < 3)
282 {
283 fclose(fp);
284 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
285 return;
286 }
287
288 if (fwrite (&ibuff2, 2, 1, fp) < 1)
289 {
290 fclose(fp);
291 this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
292 return;
293 }
294 }
295 fclose (fp);
296 }
297
298 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)299 void vtkSTLWriter::PrintSelf(ostream& os, vtkIndent indent)
300 {
301 this->Superclass::PrintSelf(os,indent);
302 }
303
304 //----------------------------------------------------------------------------
GetInput()305 vtkPolyData* vtkSTLWriter::GetInput()
306 {
307 return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
308 }
309
310 //----------------------------------------------------------------------------
GetInput(int port)311 vtkPolyData* vtkSTLWriter::GetInput(int port)
312 {
313 return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
314 }
315
316 //----------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)317 int vtkSTLWriter::FillInputPortInformation(int, vtkInformation *info)
318 {
319 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
320 return 1;
321 }
322