1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkPolyDataWriter.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 "vtkHoudiniPolyDataWriter.h"
16
17 #include <algorithm>
18
19 #include "vtkAbstractArray.h"
20 #include "vtkCellData.h"
21 #include "vtkCharArray.h"
22 #include "vtkInformation.h"
23 #include "vtkIntArray.h"
24 #include "vtkDoubleArray.h"
25 #include "vtkFloatArray.h"
26 #include "vtkLongArray.h"
27 #include "vtkLongLongArray.h"
28 #include "vtkNew.h"
29 #include "vtkPointData.h"
30 #include "vtkPoints.h"
31 #include "vtkPolyData.h"
32 #include "vtkSetGet.h"
33 #include "vtkSignedCharArray.h"
34 #include "vtkShortArray.h"
35 #include "vtkStdString.h"
36 #include "vtkStringArray.h"
37 #include "vtkUnsignedIntArray.h"
38 #include "vtkUnsignedLongArray.h"
39 #include "vtkUnsignedLongLongArray.h"
40 #include "vtkUnsignedShortArray.h"
41
42 vtkStandardNewMacro(vtkHoudiniPolyDataWriter);
43
44 namespace
45 {
46 // Houdini geometry files store point/cell data in-line with the point/cell
47 // definition. So, the point data access pattern is to write a point's
48 // coordinates, followed by its data values for each point data attribute.
49 // This storage pattern differs from VTK's, where all points are
50 // logically held in a contiguous memory block, followed by all of the values
51 // for a single data attribute. To accommodate this discrepancy in data
52 // access, we construct a facade for point/cell attributes that allows us to
53 // stream all of the values associated with a single point/cell.
54
55 struct AttributeBase
56 {
57 virtual ~AttributeBase() = default;
58 virtual void StreamHeader(std::ostream&) const = 0;
59 virtual void StreamData(std::ostream&, vtkIdType) const = 0;
60 };
61
62 template <int AttributeId>
63 struct AttributeTrait;
64
65 #define DefineAttributeTrait(attId, attType, attName, vtkArray, attDefault) \
66 template <> \
67 struct AttributeTrait<attId> \
68 { \
69 typedef attType Type; \
70 typedef vtkArray vtkArrayType; \
71 std::string Name() const { return std::string(attName); } \
72 attType Default() const { return static_cast<attType>(attDefault); } \
73 static void Get(vtkIdType index, attType* in, vtkArray* array) \
74 { array->GetTypedTuple(index, in); } \
75 static void Stream(std::ostream& out, attType t) { out << t; } \
76 }
77
78 DefineAttributeTrait(VTK_DOUBLE, double, "float", vtkDoubleArray, 0.0);
79 DefineAttributeTrait(VTK_FLOAT, float, "float", vtkFloatArray, 0.0);
80 DefineAttributeTrait(VTK_LONG_LONG, long long, "int", vtkLongLongArray, 0);
81 DefineAttributeTrait(VTK_UNSIGNED_LONG_LONG, unsigned long long, "int", vtkUnsignedLongLongArray, 0);
82 DefineAttributeTrait(VTK_ID_TYPE, vtkIdType, "int", vtkIdTypeArray, 0);
83 DefineAttributeTrait(VTK_LONG, long, "int", vtkLongArray, 0);
84 DefineAttributeTrait(VTK_UNSIGNED_LONG, unsigned long, "int", vtkUnsignedLongArray, 0);
85 DefineAttributeTrait(VTK_INT, int, "int", vtkIntArray, 0);
86 DefineAttributeTrait(VTK_UNSIGNED_INT, unsigned int, "int", vtkUnsignedIntArray, 0);
87 DefineAttributeTrait(VTK_SHORT, short, "int", vtkShortArray, 0);
88 DefineAttributeTrait(VTK_UNSIGNED_SHORT, unsigned short, "int", vtkUnsignedShortArray, 0);
89
90 #undef DefineAttributeTrait
91
92 template <>
93 struct AttributeTrait<VTK_CHAR>
94 {
95 typedef char Type;
96 typedef vtkCharArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait97 std::string Name() const { return std::string("int"); }
Default__anonac7eafc90111::AttributeTrait98 int Default() const { return static_cast<int>('0'); }
Get__anonac7eafc90111::AttributeTrait99 static void Get(vtkIdType index, char* in, vtkCharArray* array)
100 { array->GetTypedTuple(index, in); }
Stream__anonac7eafc90111::AttributeTrait101 static void Stream(std::ostream& out, char t)
102 {
103 out << static_cast<int>(t);
104 }
105 };
106
107 template <>
108 struct AttributeTrait<VTK_SIGNED_CHAR>
109 {
110 typedef signed char Type;
111 typedef vtkSignedCharArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait112 std::string Name() const { return std::string("int"); }
Default__anonac7eafc90111::AttributeTrait113 int Default() const { return static_cast<int>('0'); }
Get__anonac7eafc90111::AttributeTrait114 static void Get(vtkIdType index, signed char* in, vtkSignedCharArray* array)
115 { array->GetTypedTuple(index, in); }
Stream__anonac7eafc90111::AttributeTrait116 static void Stream(std::ostream& out, signed char t)
117 {
118 out << static_cast<int>(t);
119 }
120 };
121
122 template <>
123 struct AttributeTrait<VTK_UNSIGNED_CHAR>
124 {
125 typedef unsigned char Type;
126 typedef vtkUnsignedCharArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait127 std::string Name() const { return std::string("int"); }
Default__anonac7eafc90111::AttributeTrait128 int Default() const { return static_cast<int>('0'); }
Get__anonac7eafc90111::AttributeTrait129 static void Get(vtkIdType index, unsigned char* in,
130 vtkUnsignedCharArray* array)
131 { array->GetTypedTuple(index, in); }
Stream__anonac7eafc90111::AttributeTrait132 static void Stream(std::ostream& out, unsigned char t)
133 {
134 out << static_cast<int>(t);
135 }
136 };
137
138 template <>
139 struct AttributeTrait<VTK_STRING>
140 {
141 typedef vtkStdString Type;
142 typedef vtkStringArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait143 std::string Name() const { return std::string("string"); }
Default__anonac7eafc90111::AttributeTrait144 vtkStdString Default() const { return vtkStdString("None"); }
Get__anonac7eafc90111::AttributeTrait145 static void Get(vtkIdType index, vtkStdString* in, vtkStringArray* array)
146 {
147 assert(array->GetNumberOfComponents() == 1);
148 *in = array->GetValue(index);
149 }
Stream__anonac7eafc90111::AttributeTrait150 static void Stream(std::ostream& out, const vtkStdString& t)
151 {
152 std::size_t i = 0;
153 out << "\'";
154 for (; i < (t.size() < 32 ? t.size() : 32); i++)
155 {
156 out << t[i];
157 }
158 for (; i < 32; i++)
159 {
160 out << " ";
161 }
162 out << "\'";
163 }
164 };
165
166 template <int AttributeId>
167 struct Attribute : public AttributeBase
168 {
169 typedef typename AttributeTrait<AttributeId>::vtkArrayType vtkArrayType;
170
Attribute__anonac7eafc90111::Attribute171 Attribute(vtkAbstractArray* array) : AttributeBase()
172 {
173 this->Array = vtkArrayType::SafeDownCast(array);
174 assert(this->Array != nullptr);
175 this->Value.resize(this->Array->GetNumberOfComponents());
176 }
177
StreamHeader__anonac7eafc90111::Attribute178 void StreamHeader(std::ostream& out) const override
179 {
180 std::string s = this->Array->GetName();
181 std::replace(s.begin(), s.end(), ' ', '_');
182 std::replace(s.begin(), s.end(), '\t', '-');
183
184 AttributeTrait<AttributeId> trait;
185 out << s << " " << this->Array->GetNumberOfComponents() << " "
186 << trait.Name() << " " << trait.Default();
187 for (int i = 1; i < this->Array->GetNumberOfComponents(); i++)
188 {
189 out << " ";
190 AttributeTrait<AttributeId>::Stream(out, trait.Default());
191 }
192 }
193
StreamData__anonac7eafc90111::Attribute194 void StreamData(std::ostream& out, vtkIdType index) const override
195 {
196 assert(index < this->Array->GetNumberOfTuples());
197
198 AttributeTrait<AttributeId>::Get(index, &this->Value[0], this->Array);
199 AttributeTrait<AttributeId>::Stream(out, this->Value[0]);
200
201 for (int i = 1; i < this->Array->GetNumberOfComponents(); i++)
202 {
203 out << " ";
204 AttributeTrait<AttributeId>::Stream(out, this->Value[i]);
205 }
206 }
207
208 protected:
209 mutable std::vector<typename AttributeTrait<AttributeId>::Type> Value;
210 mutable vtkArrayType* Array;
211 };
212
213 class Attributes
214 {
215 public:
216 typedef std::vector<AttributeBase*>::iterator AttIt;
217
218 class Header
219 {
220 friend class Attributes;
Header(Attributes * atts)221 Header(Attributes* atts) : Atts(atts) {}
222 void operator=(const Attributes::Header&) = delete;
223
operator <<(ostream & out,const Attributes::Header & header)224 friend ostream& operator<<(ostream& out, const Attributes::Header& header)
225 {
226 for (Attributes::AttIt it=header.Atts->AttVec.begin();
227 it != header.Atts->AttVec.end(); ++it)
228 {
229 (*it)->StreamHeader(out);
230 out << endl;
231 }
232 return out;
233 }
234 public:
235 Attributes* Atts;
236 };
237
238 class Component
239 {
240 friend class Attributes;
241
Component(Attributes * atts,vtkIdType index)242 Component(Attributes* atts, vtkIdType index) : Atts(atts),
243 Index(index) {}
244
245 Attributes* Atts;
246 vtkIdType Index;
247
operator <<(ostream & out,const Attributes::Component & component)248 friend ostream& operator<<(ostream& out,
249 const Attributes::Component& component)
250 {
251 for (Attributes::AttIt it=component.Atts->AttVec.begin();
252 it != component.Atts->AttVec.end(); ++it)
253 {
254 (*it)->StreamData(out, component.Index);
255
256 if (it + 1 != component.Atts->AttVec.end())
257 {
258 out << " ";
259 }
260 }
261 return out;
262 }
263 };
264
Attributes()265 Attributes() : Hdr(nullptr) { this->Hdr.Atts = this; }
~Attributes()266 virtual ~Attributes()
267 {
268 for (AttIt it=this->AttVec.begin(); it != this->AttVec.end(); ++it)
269 {
270 delete *it;
271 }
272 }
273
GetHeader()274 Header& GetHeader() { return this->Hdr; }
275
operator [](vtkIdType i)276 Component operator[](vtkIdType i)
277 {
278 return Attributes::Component(this, i);
279 }
280
281 template <int TypeId>
AddAttribute(vtkAbstractArray * array)282 void AddAttribute(vtkAbstractArray* array)
283 {
284 this->AttVec.push_back(new Attribute<TypeId>(array));
285 }
286
287 Header Hdr;
288 std::vector<AttributeBase*> AttVec;
289 };
290
291 template <int TypeId>
AddAttribute(Attributes & atts,vtkAbstractArray * array)292 void AddAttribute(Attributes& atts, vtkAbstractArray* array)
293 {
294 atts.AddAttribute<TypeId>(array);
295 }
296 }
297
298 //----------------------------------------------------------------------------
vtkHoudiniPolyDataWriter()299 vtkHoudiniPolyDataWriter::vtkHoudiniPolyDataWriter()
300 {
301 this->FileName = nullptr;
302 }
303
304 //----------------------------------------------------------------------------
~vtkHoudiniPolyDataWriter()305 vtkHoudiniPolyDataWriter::~vtkHoudiniPolyDataWriter()
306 {
307 this->SetFileName(nullptr);
308 }
309
310 //----------------------------------------------------------------------------
WriteData()311 void vtkHoudiniPolyDataWriter::WriteData()
312 {
313 // Grab the input data
314 vtkPolyData* input = vtkPolyData::SafeDownCast(this->GetInput());
315 if (!input)
316 {
317 vtkErrorMacro(<< "Missing input polydata!");
318 return;
319 }
320
321 // Open the file for streaming
322 std::ofstream file(this->FileName, std::ofstream::out);
323
324 if (file.fail())
325 {
326 vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
327 return;
328 }
329
330 vtkIdType nPrims = 0;
331 {
332 nPrims += input->GetNumberOfVerts();
333 nPrims += input->GetNumberOfLines();
334 nPrims += input->GetNumberOfPolys();
335
336 vtkCellArray* stripArray = input->GetStrips();
337 vtkIdType nPts, *pts;
338
339 stripArray->InitTraversal();
340 while (stripArray->GetNextCell(nPts, pts))
341 {
342 nPrims += nPts - 2;
343 }
344 }
345
346 // Write generic header info
347 file << "PGEOMETRY V2" << endl;
348 file << "NPoints " << input->GetNumberOfPoints() << " "
349 << "NPrims " << nPrims << endl;
350 file << "NPointGroups " << 0 << " NPrimGroups " << 0 << endl;
351 file << "NPointAttrib " << input->GetPointData()->GetNumberOfArrays()<< " "
352 << "NVertexAttrib " << 0 << " "
353 << "NPrimAttrib " << input->GetCellData()->GetNumberOfArrays() << " "
354 << "NAttrib " << 0 << endl;
355
356 #define vtkHoudiniTemplateMacroCase(typeN, atts, arr) \
357 case typeN: { AddAttribute<typeN>(atts, arr); }; break
358 #define vtkHoudiniTemplateMacro(atts, arr) \
359 vtkHoudiniTemplateMacroCase(VTK_DOUBLE, atts, arr); \
360 vtkHoudiniTemplateMacroCase(VTK_FLOAT, atts, arr); \
361 vtkHoudiniTemplateMacroCase(VTK_LONG_LONG, atts, arr); \
362 vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_LONG_LONG, atts, arr); \
363 vtkHoudiniTemplateMacroCase(VTK_ID_TYPE, atts, arr); \
364 vtkHoudiniTemplateMacroCase(VTK_LONG, atts, arr); \
365 vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_LONG, atts, arr); \
366 vtkHoudiniTemplateMacroCase(VTK_INT, atts, arr); \
367 vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_INT, atts, arr); \
368 vtkHoudiniTemplateMacroCase(VTK_SHORT, atts, arr); \
369 vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_SHORT, atts, arr); \
370 vtkHoudiniTemplateMacroCase(VTK_CHAR, atts, arr); \
371 vtkHoudiniTemplateMacroCase(VTK_SIGNED_CHAR, atts, arr); \
372 vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_CHAR, atts, arr)
373
374 // Construct Attributes instance for points
375 Attributes pointAttributes;
376 for (vtkIdType i = 0; i < input->GetPointData()->GetNumberOfArrays(); i++)
377 {
378 vtkAbstractArray* array = input->GetPointData()->GetAbstractArray(i);
379 switch (array->GetDataType())
380 {
381 vtkHoudiniTemplateMacro(pointAttributes, array);
382 #if 0
383 case VTK_STRING: { AddAttribute<VTK_STRING>(pointAttributes, array); }; break;
384 #endif
385 default:
386 vtkGenericWarningMacro(<<"Unsupported data type!");
387 }
388 }
389
390 // Write point attributes header info
391 if (input->GetPointData()->GetNumberOfArrays() != 0)
392 {
393 file << "PointAttrib" << endl;
394 file << pointAttributes.GetHeader();
395 }
396
397 // Write point data
398 vtkPoints* points = input->GetPoints();
399 double xyz[3];
400 for (vtkIdType i = 0; i < input->GetNumberOfPoints(); i++)
401 {
402 points->GetPoint(i, xyz);
403 file << xyz[0] << " " << xyz[1] << " " << xyz[2] << " "
404 << 1;
405 if (input->GetPointData()->GetNumberOfArrays() != 0)
406 {
407 file << " (" << pointAttributes[i] << ")";
408 }
409 file << endl;
410 }
411
412 // Construct Attributes instance for cells
413 Attributes cellAttributes;
414 for (vtkIdType i = 0; i < input->GetCellData()->GetNumberOfArrays(); i++)
415 {
416 vtkAbstractArray* array = input->GetCellData()->GetAbstractArray(i);
417 switch (array->GetDataType())
418 {
419 vtkHoudiniTemplateMacro(cellAttributes, array);
420 #if 0
421 case VTK_STRING: { AddAttribute<VTK_STRING>(cellAttributes, array); }; break;
422 #endif
423 default:
424 vtkGenericWarningMacro(<<"Unsupported data type!");
425 }
426 }
427
428 #undef vtkHoudiniTemplateMacro
429 #undef vtkHoudiniTemplateMacroCase
430
431 // Write cell attributes header info
432 if (input->GetCellData()->GetNumberOfArrays() != 0 &&
433 input->GetNumberOfCells() != 0)
434 {
435 file << "PrimitiveAttrib" << endl;
436 file << cellAttributes.GetHeader();
437 }
438
439 if (input->GetNumberOfVerts() != 0)
440 {
441 // Write vertex data as a particle system
442 vtkCellArray* vertArray = input->GetVerts();
443 vtkIdType nPts, *pts, cellId;
444
445 if (input->GetNumberOfVerts() > 1)
446 {
447 file << "Run " << input->GetNumberOfVerts() << " Part" << endl;
448 }
449 else
450 {
451 file << "Part ";
452 }
453 cellId = 0;
454
455 vertArray->InitTraversal();
456 while (vertArray->GetNextCell(nPts, pts))
457 {
458 file << nPts;
459 for (vtkIdType i = 0; i < nPts; i++)
460 {
461 file << " " << pts[i];
462 }
463 if (input->GetCellData()->GetNumberOfArrays() != 0)
464 {
465 file << " [" << cellAttributes[cellId] << "]";
466 }
467 file << endl;
468 cellId++;
469 }
470 }
471
472 if (input->GetNumberOfLines() != 0)
473 {
474 // Write line data as open polygons
475 file << "Run " << input->GetNumberOfLines() << " Poly" <<endl;
476
477 vtkCellArray* lineArray = input->GetLines();
478 vtkIdType nPts, *pts, cellId;
479
480 cellId = input->GetNumberOfVerts();
481
482 lineArray->InitTraversal();
483 while (lineArray->GetNextCell(nPts, pts))
484 {
485 file << nPts << " : " << pts[0];
486 for (vtkIdType i = 1; i < nPts; i++)
487 {
488 file << " " << pts[i];
489 }
490 if (input->GetCellData()->GetNumberOfArrays() != 0)
491 {
492 file << " [" << cellAttributes[cellId++] << "]";
493 }
494 file << endl;
495 }
496 }
497
498 if (input->GetNumberOfPolys() != 0)
499 {
500 // Write polygon data
501 file << "Run " << input->GetNumberOfPolys() << " Poly" <<endl;
502
503 vtkCellArray* polyArray = input->GetPolys();
504 vtkIdType nPts, *pts, cellId;
505
506 cellId = (input->GetNumberOfVerts() + input->GetNumberOfLines());
507
508 polyArray->InitTraversal();
509 while (polyArray->GetNextCell(nPts, pts))
510 {
511 file << nPts << " < " << pts[0];
512 for (vtkIdType i = 1; i < nPts; i++)
513 {
514 file << " " << pts[i];
515 }
516 if (input->GetCellData()->GetNumberOfArrays() != 0)
517 {
518 file << " [" << cellAttributes[cellId++] << "]";
519 }
520 file << endl;
521 }
522 }
523
524 if (input->GetNumberOfStrips() != 0)
525 {
526 // Write triangle strip data as polygons
527 vtkCellArray* stripArray = input->GetStrips();
528 vtkIdType nPts, *pts, cellId;
529
530 cellId = (input->GetNumberOfVerts() +
531 input->GetNumberOfLines() +
532 input->GetNumberOfPolys());
533
534 stripArray->InitTraversal();
535 while (stripArray->GetNextCell(nPts, pts))
536 {
537 if (nPts > 3)
538 {
539 file << "Run " << nPts - 2 << " Poly" << endl;
540 }
541 else
542 {
543 file << "Poly ";
544 }
545
546 for (vtkIdType i = 2; i < nPts; i++)
547 {
548 if (i%2 == 0)
549 {
550 file << "3 < "
551 << pts[i - 2] << " " << pts[i - 1] << " " << pts[i];
552 }
553 else
554 {
555 file << "3 < "
556 << pts[i - 1] << " " << pts[i - 2] << " " << pts[i];
557 }
558 if (input->GetCellData()->GetNumberOfArrays() != 0)
559 {
560 file << " [" << cellAttributes[cellId] << "]";
561 }
562 file << endl;
563 }
564 cellId++;
565 }
566 }
567
568 file << "beginExtra" << endl;
569 file << "endExtra" << endl;
570
571 file.close();
572 }
573
574 //----------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)575 int vtkHoudiniPolyDataWriter::FillInputPortInformation(int, vtkInformation *info)
576 {
577 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
578 return 1;
579 }
580
581 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)582 void vtkHoudiniPolyDataWriter::PrintSelf(ostream& os, vtkIndent indent)
583 {
584 this->Superclass::PrintSelf(os, indent);
585 os << indent << "FileName: "
586 << (this->FileName? this->FileName:"(none)") << "\n";
587 }
588