/*========================================================================= Program: Visualization Toolkit Module: vtkDataWriter.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkDataWriter.h" #include "vtkBitArray.h" #include "vtkByteSwap.h" #include "vtkCellArray.h" #include "vtkCellArrayIterator.h" #include "vtkCellData.h" #include "vtkCharArray.h" #include "vtkDataSet.h" #include "vtkDoubleArray.h" #include "vtkErrorCode.h" #include "vtkExecutive.h" #include "vtkFieldData.h" #include "vtkFloatArray.h" #include "vtkGraph.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationDoubleKey.h" #include "vtkInformationDoubleVectorKey.h" #include "vtkInformationIdTypeKey.h" #include "vtkInformationIntegerKey.h" #include "vtkInformationIntegerVectorKey.h" #include "vtkInformationIterator.h" #include "vtkInformationKeyLookup.h" #include "vtkInformationStringKey.h" #include "vtkInformationStringVectorKey.h" #include "vtkInformationUnsignedLongKey.h" #include "vtkIntArray.h" #include "vtkLegacyReaderVersion.h" #include "vtkLongArray.h" #include "vtkLookupTable.h" #include "vtkMath.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #ifdef VTK_USE_SCALED_SOA_ARRAYS #include "vtkScaledSOADataArrayTemplate.h" #endif #include "vtkSOADataArrayTemplate.h" #include "vtkShortArray.h" #include "vtkSignedCharArray.h" #include "vtkStringArray.h" #include "vtkTable.h" #include "vtkTypeInt64Array.h" #include "vtkTypeTraits.h" #include "vtkTypeUInt64Array.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedIntArray.h" #include "vtkUnsignedLongArray.h" #include "vtkUnsignedShortArray.h" #include "vtkVariantArray.h" #include "vtksys/FStream.hxx" #include #include vtkStandardNewMacro(vtkDataWriter); //------------------------------------------------------------------------------ // Created object with a default header, ASCII format, and default names for // scalars, vectors, tensors, normals, and texture coordinates. vtkDataWriter::vtkDataWriter() { this->FileName = nullptr; this->Header = new char[257]; strcpy(this->Header, "vtk output"); this->FileType = VTK_ASCII; this->FileVersion = VTK_LEGACY_READER_VERSION_5_1; this->ScalarsName = nullptr; this->VectorsName = nullptr; this->TensorsName = nullptr; this->NormalsName = nullptr; this->TCoordsName = nullptr; this->GlobalIdsName = nullptr; this->PedigreeIdsName = nullptr; this->EdgeFlagsName = nullptr; this->LookupTableName = new char[13]; strcpy(this->LookupTableName, "lookup_table"); this->FieldDataName = new char[10]; strcpy(this->FieldDataName, "FieldData"); this->WriteToOutputString = 0; this->OutputString = nullptr; this->OutputStringLength = 0; this->WriteArrayMetaData = true; } //------------------------------------------------------------------------------ vtkDataWriter::~vtkDataWriter() { delete[] this->FileName; delete[] this->Header; delete[] this->ScalarsName; delete[] this->VectorsName; delete[] this->TensorsName; delete[] this->NormalsName; delete[] this->TCoordsName; delete[] this->GlobalIdsName; delete[] this->PedigreeIdsName; delete[] this->EdgeFlagsName; delete[] this->LookupTableName; delete[] this->FieldDataName; delete[] this->OutputString; this->OutputString = nullptr; this->OutputStringLength = 0; } //------------------------------------------------------------------------------ // Open a vtk data file. Returns nullptr if error. ostream* vtkDataWriter::OpenVTKFile() { // Save current locale settings and set standard one to // avoid locale issues - for instance with the decimal separator. this->CurrentLocale = std::locale::global(std::locale::classic()); ostream* fptr; if ((!this->WriteToOutputString) && (!this->FileName)) { vtkErrorMacro(<< "No FileName specified! Can't write!"); this->SetErrorCode(vtkErrorCode::NoFileNameError); return nullptr; } vtkDebugMacro(<< "Opening vtk file for writing..."); if (this->WriteToOutputString) { // Get rid of any old output string. delete[] this->OutputString; this->OutputString = nullptr; this->OutputStringLength = 0; // Allocate the new output string. (Note: this will only work with binary). if (!this->GetInputExecutive(0, 0)) { vtkErrorMacro(<< "No input! Can't write!"); return nullptr; } this->GetInputExecutive(0, 0)->Update(); /// OutputString will be allocated on CloseVTKFile(). /// this->OutputStringAllocatedLength = /// static_cast (500+ 1024 * input->GetActualMemorySize()); /// this->OutputString = new char[this->OutputStringAllocatedLength]; fptr = new std::ostringstream; } else { if (this->FileType == VTK_ASCII) { fptr = new vtksys::ofstream(this->FileName, ios::out); } else { #ifdef _WIN32 fptr = new vtksys::ofstream(this->FileName, ios::out | ios::binary); #else fptr = new vtksys::ofstream(this->FileName, ios::out); #endif } } if (fptr->fail()) { vtkErrorMacro(<< "Unable to open file: " << this->FileName); this->SetErrorCode(vtkErrorCode::CannotOpenFileError); delete fptr; return nullptr; } return fptr; } //------------------------------------------------------------------------------ void vtkDataWriter::SetFileVersion(int version) { if (version == this->FileVersion) { return; } this->Modified(); this->FileVersion = version; this->FileMajorVersion = version / 10; this->FileMinorVersion = version - (10 * this->FileMajorVersion); } //------------------------------------------------------------------------------ // Write the header of a vtk data file. Returns 0 if error. int vtkDataWriter::WriteHeader(ostream* fp) { vtkDebugMacro(<< "Writing header..."); // This code will update as the compile time // major and minor versions are updated. int majVersion, minVersion; if (this->FileVersion == VTK_LEGACY_READER_VERSION_4_2) { majVersion = 4; minVersion = 2; } else if (this->FileVersion == VTK_LEGACY_READER_VERSION_5_1) { majVersion = 5; minVersion = 1; } else // future? { majVersion = vtkLegacyReaderMajorVersion; minVersion = vtkLegacyReaderMinorVersion; } *fp << "# vtk DataFile Version " << majVersion << "." << minVersion << "\n"; *fp << this->Header << "\n"; if (this->FileType == VTK_ASCII) { *fp << "ASCII\n"; } else { *fp << "BINARY\n"; } fp->flush(); if (fp->fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return 0; } return 1; } //------------------------------------------------------------------------------ // Write the cell data (e.g., scalars, vectors, ...) of a vtk dataset. // Returns 0 if error. int vtkDataWriter::WriteCellData(ostream* fp, vtkDataSet* ds) { vtkIdType numCells; vtkDataArray* scalars; vtkDataArray* vectors; vtkDataArray* normals; vtkDataArray* tcoords; vtkDataArray* tensors; vtkDataArray* globalIds; vtkAbstractArray* pedigreeIds; vtkFieldData* field; vtkCellData* cd = ds->GetCellData(); vtkDebugMacro(<< "Writing cell data..."); numCells = ds->GetNumberOfCells(); if (numCells <= 0) { vtkDebugMacro(<< "No cell data to write!"); return 1; } scalars = cd->GetScalars(); if (scalars && scalars->GetNumberOfTuples() <= 0) scalars = nullptr; vectors = cd->GetVectors(); if (vectors && vectors->GetNumberOfTuples() <= 0) vectors = nullptr; normals = cd->GetNormals(); if (normals && normals->GetNumberOfTuples() <= 0) normals = nullptr; tcoords = cd->GetTCoords(); if (tcoords && tcoords->GetNumberOfTuples() <= 0) tcoords = nullptr; tensors = cd->GetTensors(); if (tensors && tensors->GetNumberOfTuples() <= 0) tensors = nullptr; globalIds = cd->GetGlobalIds(); if (globalIds && globalIds->GetNumberOfTuples() <= 0) globalIds = nullptr; pedigreeIds = cd->GetPedigreeIds(); if (pedigreeIds && pedigreeIds->GetNumberOfTuples() <= 0) pedigreeIds = nullptr; field = cd; if (field && field->GetNumberOfTuples() <= 0) field = nullptr; if (!(scalars || vectors || normals || tcoords || tensors || globalIds || pedigreeIds || field)) { vtkDebugMacro(<< "No cell data to write!"); return 1; } *fp << "CELL_DATA " << numCells << "\n"; // // Write scalar data // if (scalars) { if (!this->WriteScalarData(fp, scalars, numCells)) { return 0; } } // // Write vector data // if (vectors) { if (!this->WriteVectorData(fp, vectors, numCells)) { return 0; } } // // Write normals // if (normals) { if (!this->WriteNormalData(fp, normals, numCells)) { return 0; } } // // Write texture coords // if (tcoords) { if (!this->WriteTCoordData(fp, tcoords, numCells)) { return 0; } } // // Write tensors // if (tensors) { if (!this->WriteTensorData(fp, tensors, numCells)) { return 0; } } // // Write global ids // if (globalIds) { if (!this->WriteGlobalIdData(fp, globalIds, numCells)) { return 0; } } // // Write pedigree ids // if (pedigreeIds) { if (!this->WritePedigreeIdData(fp, pedigreeIds, numCells)) { return 0; } } // // Write field // if (field) { if (!this->WriteFieldData(fp, field)) { return 0; } } return 1; } //------------------------------------------------------------------------------ // Write the point data (e.g., scalars, vectors, ...) of a vtk dataset. // Returns 0 if error. int vtkDataWriter::WritePointData(ostream* fp, vtkDataSet* ds) { vtkIdType numPts; vtkDataArray* scalars; vtkDataArray* vectors; vtkDataArray* normals; vtkDataArray* tcoords; vtkDataArray* tensors; vtkDataArray* globalIds; vtkAbstractArray* pedigreeIds; vtkDataArray* edgeFlags; vtkFieldData* field; vtkPointData* pd = ds->GetPointData(); vtkDebugMacro(<< "Writing point data..."); numPts = ds->GetNumberOfPoints(); if (numPts <= 0) { vtkDebugMacro(<< "No point data to write!"); return 1; } scalars = pd->GetScalars(); if (scalars && scalars->GetNumberOfTuples() <= 0) scalars = nullptr; vectors = pd->GetVectors(); if (vectors && vectors->GetNumberOfTuples() <= 0) vectors = nullptr; normals = pd->GetNormals(); if (normals && normals->GetNumberOfTuples() <= 0) normals = nullptr; tcoords = pd->GetTCoords(); if (tcoords && tcoords->GetNumberOfTuples() <= 0) tcoords = nullptr; tensors = pd->GetTensors(); if (tensors && tensors->GetNumberOfTuples() <= 0) tensors = nullptr; globalIds = pd->GetGlobalIds(); if (globalIds && globalIds->GetNumberOfTuples() <= 0) globalIds = nullptr; pedigreeIds = pd->GetPedigreeIds(); if (pedigreeIds && pedigreeIds->GetNumberOfTuples() <= 0) pedigreeIds = nullptr; edgeFlags = pd->GetAttribute(vtkDataSetAttributes::EDGEFLAG); if (edgeFlags && edgeFlags->GetNumberOfTuples() <= 0) edgeFlags = nullptr; field = pd; if (field && field->GetNumberOfTuples() <= 0) field = nullptr; if (!(scalars || vectors || normals || tcoords || tensors || globalIds || pedigreeIds || edgeFlags || field)) { vtkDebugMacro(<< "No point data to write!"); return 1; } *fp << "POINT_DATA " << numPts << "\n"; // // Write scalar data // if (scalars) { if (!this->WriteScalarData(fp, scalars, numPts)) { return 0; } } // // Write vector data // if (vectors) { if (!this->WriteVectorData(fp, vectors, numPts)) { return 0; } } // // Write normals // if (normals) { if (!this->WriteNormalData(fp, normals, numPts)) { return 0; } } // // Write texture coords // if (tcoords) { if (!this->WriteTCoordData(fp, tcoords, numPts)) { return 0; } } // // Write tensors // if (tensors) { if (!this->WriteTensorData(fp, tensors, numPts)) { return 0; } } // // Write global ids // if (globalIds) { if (!this->WriteGlobalIdData(fp, globalIds, numPts)) { return 0; } } // // Write pedigree ids // if (pedigreeIds) { if (!this->WritePedigreeIdData(fp, pedigreeIds, numPts)) { return 0; } } // // Write edge flags // if (edgeFlags) { if (!this->WriteEdgeFlagsData(fp, edgeFlags, numPts)) { return 0; } } // // Write field // if (field) { if (!this->WriteFieldData(fp, field)) { return 0; } } return 1; } //------------------------------------------------------------------------------ // Write the vertex data (e.g., scalars, vectors, ...) of a vtk graph. // Returns 0 if error. int vtkDataWriter::WriteVertexData(ostream* fp, vtkGraph* ds) { vtkIdType numVertices; vtkDataArray* scalars; vtkDataArray* vectors; vtkDataArray* normals; vtkDataArray* tcoords; vtkDataArray* tensors; vtkDataArray* globalIds; vtkAbstractArray* pedigreeIds; vtkFieldData* field; vtkDataSetAttributes* cd = ds->GetVertexData(); vtkDebugMacro(<< "Writing vertex data..."); numVertices = ds->GetNumberOfVertices(); if (numVertices <= 0) { vtkDebugMacro(<< "No vertex data to write!"); return 1; } scalars = cd->GetScalars(); if (scalars && scalars->GetNumberOfTuples() <= 0) scalars = nullptr; vectors = cd->GetVectors(); if (vectors && vectors->GetNumberOfTuples() <= 0) vectors = nullptr; normals = cd->GetNormals(); if (normals && normals->GetNumberOfTuples() <= 0) normals = nullptr; tcoords = cd->GetTCoords(); if (tcoords && tcoords->GetNumberOfTuples() <= 0) tcoords = nullptr; tensors = cd->GetTensors(); if (tensors && tensors->GetNumberOfTuples() <= 0) tensors = nullptr; globalIds = cd->GetGlobalIds(); if (globalIds && globalIds->GetNumberOfTuples() <= 0) globalIds = nullptr; pedigreeIds = cd->GetPedigreeIds(); if (pedigreeIds && pedigreeIds->GetNumberOfTuples() <= 0) pedigreeIds = nullptr; field = cd; if (field && field->GetNumberOfTuples() <= 0) field = nullptr; if (!(scalars || vectors || normals || tcoords || tensors || globalIds || pedigreeIds || field)) { vtkDebugMacro(<< "No cell data to write!"); return 1; } *fp << "VERTEX_DATA " << numVertices << "\n"; // // Write scalar data // if (scalars) { if (!this->WriteScalarData(fp, scalars, numVertices)) { return 0; } } // // Write vector data // if (vectors) { if (!this->WriteVectorData(fp, vectors, numVertices)) { return 0; } } // // Write normals // if (normals) { if (!this->WriteNormalData(fp, normals, numVertices)) { return 0; } } // // Write texture coords // if (tcoords) { if (!this->WriteTCoordData(fp, tcoords, numVertices)) { return 0; } } // // Write tensors // if (tensors) { if (!this->WriteTensorData(fp, tensors, numVertices)) { return 0; } } // // Write global ids // if (globalIds) { if (!this->WriteGlobalIdData(fp, globalIds, numVertices)) { return 0; } } // // Write pedigree ids // if (pedigreeIds) { if (!this->WritePedigreeIdData(fp, pedigreeIds, numVertices)) { return 0; } } // // Write field // if (field) { if (!this->WriteFieldData(fp, field)) { return 0; } } return 1; } //------------------------------------------------------------------------------ // Write the edge data (e.g., scalars, vectors, ...) of a vtk graph. // Returns 0 if error. int vtkDataWriter::WriteEdgeData(ostream* fp, vtkGraph* g) { vtkIdType numEdges; vtkDataArray* scalars; vtkDataArray* vectors; vtkDataArray* normals; vtkDataArray* tcoords; vtkDataArray* tensors; vtkDataArray* globalIds; vtkAbstractArray* pedigreeIds; vtkFieldData* field; vtkDataSetAttributes* cd = g->GetEdgeData(); vtkDebugMacro(<< "Writing edge data..."); numEdges = g->GetNumberOfEdges(); if (numEdges <= 0) { vtkDebugMacro(<< "No edge data to write!"); return 1; } scalars = cd->GetScalars(); if (scalars && scalars->GetNumberOfTuples() <= 0) scalars = nullptr; vectors = cd->GetVectors(); if (vectors && vectors->GetNumberOfTuples() <= 0) vectors = nullptr; normals = cd->GetNormals(); if (normals && normals->GetNumberOfTuples() <= 0) normals = nullptr; tcoords = cd->GetTCoords(); if (tcoords && tcoords->GetNumberOfTuples() <= 0) tcoords = nullptr; tensors = cd->GetTensors(); if (tensors && tensors->GetNumberOfTuples() <= 0) tensors = nullptr; globalIds = cd->GetGlobalIds(); if (globalIds && globalIds->GetNumberOfTuples() <= 0) globalIds = nullptr; pedigreeIds = cd->GetPedigreeIds(); if (pedigreeIds && pedigreeIds->GetNumberOfTuples() <= 0) pedigreeIds = nullptr; field = cd; if (field && field->GetNumberOfTuples() <= 0) field = nullptr; if (!(scalars || vectors || normals || tcoords || tensors || globalIds || pedigreeIds || field)) { vtkDebugMacro(<< "No edge data to write!"); return 1; } *fp << "EDGE_DATA " << numEdges << "\n"; // // Write scalar data // if (scalars) { if (!this->WriteScalarData(fp, scalars, numEdges)) { return 0; } } // // Write vector data // if (vectors) { if (!this->WriteVectorData(fp, vectors, numEdges)) { return 0; } } // // Write normals // if (normals) { if (!this->WriteNormalData(fp, normals, numEdges)) { return 0; } } // // Write texture coords // if (tcoords) { if (!this->WriteTCoordData(fp, tcoords, numEdges)) { return 0; } } // // Write tensors // if (tensors) { if (!this->WriteTensorData(fp, tensors, numEdges)) { return 0; } } // // Write global ids // if (globalIds) { if (!this->WriteGlobalIdData(fp, globalIds, numEdges)) { return 0; } } // // Write pedigree ids // if (pedigreeIds) { if (!this->WritePedigreeIdData(fp, pedigreeIds, numEdges)) { return 0; } } // // Write field // if (field) { if (!this->WriteFieldData(fp, field)) { return 0; } } return 1; } //------------------------------------------------------------------------------ // Write the row data (e.g., scalars, vectors, ...) of a vtk table. // Returns 0 if error. int vtkDataWriter::WriteRowData(ostream* fp, vtkTable* t) { vtkIdType numRows; vtkDataArray* scalars; vtkDataArray* vectors; vtkDataArray* normals; vtkDataArray* tcoords; vtkDataArray* tensors; vtkDataArray* globalIds; vtkAbstractArray* pedigreeIds; vtkFieldData* field; vtkDataSetAttributes* cd = t->GetRowData(); numRows = t->GetNumberOfRows(); vtkDebugMacro(<< "Writing row data..."); scalars = cd->GetScalars(); if (scalars && scalars->GetNumberOfTuples() <= 0) scalars = nullptr; vectors = cd->GetVectors(); if (vectors && vectors->GetNumberOfTuples() <= 0) vectors = nullptr; normals = cd->GetNormals(); if (normals && normals->GetNumberOfTuples() <= 0) normals = nullptr; tcoords = cd->GetTCoords(); if (tcoords && tcoords->GetNumberOfTuples() <= 0) tcoords = nullptr; tensors = cd->GetTensors(); if (tensors && tensors->GetNumberOfTuples() <= 0) tensors = nullptr; globalIds = cd->GetGlobalIds(); if (globalIds && globalIds->GetNumberOfTuples() <= 0) globalIds = nullptr; pedigreeIds = cd->GetPedigreeIds(); if (pedigreeIds && pedigreeIds->GetNumberOfTuples() <= 0) pedigreeIds = nullptr; field = cd; if (field && field->GetNumberOfTuples() <= 0) field = nullptr; if (!(scalars || vectors || normals || tcoords || tensors || globalIds || pedigreeIds || field)) { vtkDebugMacro(<< "No row data to write!"); return 1; } *fp << "ROW_DATA " << numRows << "\n"; // // Write scalar data // if (scalars) { if (!this->WriteScalarData(fp, scalars, numRows)) { return 0; } } // // Write vector data // if (vectors) { if (!this->WriteVectorData(fp, vectors, numRows)) { return 0; } } // // Write normals // if (normals) { if (!this->WriteNormalData(fp, normals, numRows)) { return 0; } } // // Write texture coords // if (tcoords) { if (!this->WriteTCoordData(fp, tcoords, numRows)) { return 0; } } // // Write tensors // if (tensors) { if (!this->WriteTensorData(fp, tensors, numRows)) { return 0; } } // // Write global ids // if (globalIds) { if (!this->WriteGlobalIdData(fp, globalIds, numRows)) { return 0; } } // // Write pedigree ids // if (pedigreeIds) { if (!this->WritePedigreeIdData(fp, pedigreeIds, numRows)) { return 0; } } // // Write field // if (field) { if (!this->WriteFieldData(fp, field)) { return 0; } } return 1; } namespace { // Template to handle writing data in ascii or binary // We could change the format into C++ io standard ... template void vtkWriteDataArray( ostream* fp, T* data, int fileType, const char* format, vtkIdType num, vtkIdType numComp) { vtkIdType i, j, idx, sizeT; char str[1024]; sizeT = sizeof(T); if (fileType == VTK_ASCII) { for (j = 0; j < num; j++) { for (i = 0; i < numComp; i++) { idx = i + j * numComp; snprintf(str, sizeof(str), format, *data++); *fp << str; if (!((idx + 1) % 9)) { *fp << "\n"; } } } } else { if (num * numComp > 0) { // need to byteswap ?? switch (sizeT) { case 2: // no typecast needed here; method call takes void* data vtkByteSwap::SwapWrite2BERange(data, num * numComp, fp); break; case 4: // no typecast needed here; method call takes void* data vtkByteSwap::SwapWrite4BERange(data, num * numComp, fp); break; case 8: // no typecast needed here; method call takes void* data vtkByteSwap::SwapWrite8BERange(data, num * numComp, fp); break; default: fp->write(reinterpret_cast(data), sizeof(T) * (num * numComp)); break; } } } *fp << "\n"; } //------------------------------------------------------------------------------ template Value* GetPointer(vtkAbstractArray* array) { return static_cast(array)->GetPointer(0); } //------------------------------------------------------------------------------ // Returns a pointer to the data ordered in original VTK style ordering // of the data. If this is an SOA array it has to allocate the memory // for that in which case the calling function must delete it. template T* GetArrayRawPointer(vtkAbstractArray* array, int isAOSArray) { if (isAOSArray) { return GetPointer(array); } auto nc = array->GetNumberOfComponents(); auto nt = array->GetNumberOfTuples(); T* data = new T[nc * nt]; array->ExportToVoidPointer(data); return data; } } // end anonymous namespace //------------------------------------------------------------------------------ // Write out data to file specified. int vtkDataWriter::WriteArray(ostream* fp, int dataType, vtkAbstractArray* data, const char* format, vtkIdType num, vtkIdType numComp) { vtkIdType i, j, idx; char str[1024]; bool isAOSArray = data->HasStandardMemoryLayout(); char* outputFormat = new char[10]; switch (dataType) { case VTK_BIT: { // assume that bit array is always in original AOS ordering snprintf(str, sizeof(str), format, "bit"); *fp << str; if (this->FileType == VTK_ASCII) { int s; for (j = 0; j < num; j++) { for (i = 0; i < numComp; i++) { idx = i + j * numComp; s = static_cast(data)->GetValue(idx); *fp << (s != 0.0 ? 1 : 0); if (!((idx + 1) % 8)) { *fp << "\n"; } else { *fp << " "; } } } } else { unsigned char* cptr = static_cast(data)->GetPointer(0); fp->write(reinterpret_cast(cptr), (sizeof(unsigned char)) * ((num - 1) / 8 + 1)); } *fp << "\n"; } break; case VTK_CHAR: { snprintf(str, sizeof(str), format, "char"); *fp << str; char* s = GetArrayRawPointer(data, isAOSArray); #if VTK_TYPE_CHAR_IS_SIGNED vtkWriteDataArray(fp, s, this->FileType, "%hhd ", num, numComp); #else vtkWriteDataArray(fp, s, this->FileType, "%hhu ", num, numComp); #endif if (!isAOSArray) { delete[] s; } } break; case VTK_SIGNED_CHAR: { snprintf(str, sizeof(str), format, "signed_char"); *fp << str; signed char* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%hhd ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_UNSIGNED_CHAR: { snprintf(str, sizeof(str), format, "unsigned_char"); *fp << str; unsigned char* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%hhu ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_SHORT: { snprintf(str, sizeof(str), format, "short"); *fp << str; short* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%hd ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_UNSIGNED_SHORT: { snprintf(str, sizeof(str), format, "unsigned_short"); *fp << str; unsigned short* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%hu ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_INT: { snprintf(str, sizeof(str), format, "int"); *fp << str; int* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%d ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_UNSIGNED_INT: { snprintf(str, sizeof(str), format, "unsigned_int"); *fp << str; unsigned int* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%u ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_LONG: { snprintf(str, sizeof(str), format, "long"); *fp << str; long* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%ld ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_UNSIGNED_LONG: { snprintf(str, sizeof(str), format, "unsigned_long"); *fp << str; unsigned long* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%lu ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_LONG_LONG: { snprintf(str, sizeof(str), format, "vtktypeint64"); *fp << str; long long* s = GetArrayRawPointer(data, isAOSArray); strcpy(outputFormat, vtkTypeTraits::ParseFormat()); strcat(outputFormat, " "); vtkWriteDataArray(fp, s, this->FileType, outputFormat, num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_UNSIGNED_LONG_LONG: { snprintf(str, sizeof(str), format, "vtktypeuint64"); *fp << str; unsigned long long* s = GetArrayRawPointer(data, isAOSArray); strcpy(outputFormat, vtkTypeTraits::ParseFormat()); strcat(outputFormat, " "); vtkWriteDataArray(fp, s, this->FileType, outputFormat, num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_FLOAT: { snprintf(str, sizeof(str), format, "float"); *fp << str; float* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%g ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_DOUBLE: { snprintf(str, sizeof(str), format, "double"); *fp << str; double* s = GetArrayRawPointer(data, isAOSArray); vtkWriteDataArray(fp, s, this->FileType, "%.11lg ", num, numComp); if (!isAOSArray) { delete[] s; } } break; case VTK_ID_TYPE: { // currently writing vtkIdType as int. vtkIdType size = data->GetNumberOfTuples(); std::vector intArray(size * numComp); snprintf(str, sizeof(str), format, "vtkIdType"); *fp << str; if (isAOSArray) { vtkIdType* s = static_cast(data)->GetPointer(0); for (vtkIdType jj = 0; jj < size * numComp; jj++) { intArray[jj] = s[jj]; } } else { vtkSOADataArrayTemplate* data2 = static_cast*>(data); std::vector vals(numComp); for (vtkIdType jj = 0; jj < size; jj++) { data2->GetTypedTuple(jj, &vals[0]); for (i = 0; i < numComp; i++) { intArray[jj * numComp + i] = vals[i]; } } } vtkWriteDataArray(fp, &intArray[0], this->FileType, "%d ", num, numComp); } break; case VTK_STRING: { snprintf(str, sizeof(str), format, "string"); *fp << str; if (this->FileType == VTK_ASCII) { vtkStdString s; for (j = 0; j < num; j++) { for (i = 0; i < numComp; i++) { idx = i + j * numComp; s = static_cast(data)->GetValue(idx); this->EncodeWriteString(fp, s.c_str(), false); *fp << "\n"; } } } else { vtkStdString s; for (j = 0; j < num; j++) { for (i = 0; i < numComp; i++) { idx = i + j * numComp; s = static_cast(data)->GetValue(idx); vtkTypeUInt64 length = s.length(); if (length < (static_cast(1) << 6)) { vtkTypeUInt8 len = (static_cast(3) << 6) | static_cast(length); fp->write(reinterpret_cast(&len), 1); } else if (length < (static_cast(1) << 14)) { vtkTypeUInt16 len = (static_cast(2) << 14) | static_cast(length); vtkByteSwap::SwapWrite2BERange(&len, 1, fp); } else if (length < (static_cast(1) << 30)) { vtkTypeUInt32 len = (static_cast(1) << 30) | static_cast(length); vtkByteSwap::SwapWrite4BERange(&len, 1, fp); } else { vtkByteSwap::SwapWrite8BERange(&length, 1, fp); } fp->write(s.c_str(), length); } } } *fp << "\n"; } break; case VTK_VARIANT: { snprintf(str, sizeof(str), format, "variant"); *fp << str; vtkVariant* v = static_cast(data)->GetPointer(0); for (j = 0; j < num * numComp; j++) { *fp << v[j].GetType() << " "; this->EncodeWriteString(fp, v[j].ToString().c_str(), false); *fp << endl; } } break; default: { vtkErrorMacro(<< "Type currently not supported"); *fp << "NULL_ARRAY" << endl; delete[] outputFormat; return 0; } } delete[] outputFormat; // Write out metadata if it exists: vtkInformation* info = data->GetInformation(); bool hasComponentNames = data->HasAComponentName(); bool hasInformation = info && info->GetNumberOfKeys() > 0; bool hasMetaData = hasComponentNames || hasInformation; if (this->WriteArrayMetaData && hasMetaData) { *fp << "METADATA" << endl; if (hasComponentNames) { *fp << "COMPONENT_NAMES" << endl; for (i = 0; i < numComp; ++i) { const char* compName = data->GetComponentName(i); this->EncodeWriteString(fp, compName, false); *fp << endl; } } if (hasInformation) { this->WriteInformation(fp, info); } *fp << endl; } fp->flush(); if (fp->fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return 0; } return 1; } //------------------------------------------------------------------------------ int vtkDataWriter::WritePoints(ostream* fp, vtkPoints* points) { vtkIdType numPts; if (points == nullptr) { *fp << "POINTS 0 float\n"; return 1; } numPts = points->GetNumberOfPoints(); *fp << "POINTS " << numPts << " "; return this->WriteArray(fp, points->GetDataType(), points->GetData(), "%s\n", numPts, 3); } //------------------------------------------------------------------------------ // Write out coordinates for rectilinear grids. int vtkDataWriter::WriteCoordinates(ostream* fp, vtkDataArray* coords, int axes) { int ncoords = (coords ? coords->GetNumberOfTuples() : 0); if (axes == 0) { *fp << "X_COORDINATES " << ncoords << " "; } else if (axes == 1) { *fp << "Y_COORDINATES " << ncoords << " "; } else { *fp << "Z_COORDINATES " << ncoords << " "; } if (coords) { return this->WriteArray(fp, coords->GetDataType(), coords, "%s\n", ncoords, 1); } *fp << "float\n"; return 1; } //------------------------------------------------------------------------------ // Write out scalar data. int vtkDataWriter::WriteScalarData(ostream* fp, vtkDataArray* scalars, vtkIdType num) { vtkIdType i, j, size = 0; const char* name; vtkLookupTable* lut; int dataType = scalars->GetDataType(); int numComp = scalars->GetNumberOfComponents(); if ((lut = scalars->GetLookupTable()) == nullptr || (size = lut->GetNumberOfColors()) <= 0) { name = "default"; } else { name = this->LookupTableName; } char* scalarsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->ScalarsName) { if (scalars->GetName() && strlen(scalars->GetName())) { scalarsName = new char[strlen(scalars->GetName()) * 4 + 1]; this->EncodeString(scalarsName, scalars->GetName(), true); } else { scalarsName = new char[strlen("scalars") + 1]; strcpy(scalarsName, "scalars"); } } else { scalarsName = new char[strlen(this->ScalarsName) * 4 + 1]; this->EncodeString(scalarsName, this->ScalarsName, true); } if (dataType != VTK_UNSIGNED_CHAR) { char format[1024]; *fp << "SCALARS "; if (numComp == 1) { snprintf(format, sizeof(format), "%s %%s\nLOOKUP_TABLE %s\n", scalarsName, name); } else { snprintf(format, sizeof(format), "%s %%s %d\nLOOKUP_TABLE %s\n", scalarsName, numComp, name); } delete[] scalarsName; if (this->WriteArray(fp, scalars->GetDataType(), scalars, format, num, numComp) == 0) { return 0; } } else // color scalars { int nvs = scalars->GetNumberOfComponents(); unsigned char* data = static_cast(scalars)->GetPointer(0); *fp << "COLOR_SCALARS " << scalarsName << " " << nvs << "\n"; if (this->FileType == VTK_ASCII) { for (i = 0; i < num; i++) { for (j = 0; j < nvs; j++) { *fp << (static_cast(data[nvs * i + j]) / 255.0) << " "; } if (i != 0 && !(i % 2)) { *fp << "\n"; } } } else // binary type { fp->write(reinterpret_cast(data), (sizeof(unsigned char)) * (nvs * num)); } *fp << "\n"; delete[] scalarsName; } // if lookup table, write it out if (lut && size > 0) { *fp << "LOOKUP_TABLE " << this->LookupTableName << " " << size << "\n"; if (this->FileType == VTK_ASCII) { double c[4]; for (i = 0; i < size; i++) { lut->GetTableValue(i, c); *fp << c[0] << " " << c[1] << " " << c[2] << " " << c[3] << "\n"; } } else { unsigned char* colors = lut->GetPointer(0); fp->write(reinterpret_cast(colors), (sizeof(unsigned char) * 4 * size)); } *fp << "\n"; } fp->flush(); if (fp->fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return 0; } return 1; } //------------------------------------------------------------------------------ int vtkDataWriter::WriteVectorData(ostream* fp, vtkDataArray* vectors, vtkIdType num) { *fp << "VECTORS "; char* vectorsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->VectorsName) { if (vectors->GetName() && strlen(vectors->GetName())) { vectorsName = new char[strlen(vectors->GetName()) * 4 + 1]; this->EncodeString(vectorsName, vectors->GetName(), true); } else { vectorsName = new char[strlen("vectors") + 1]; strcpy(vectorsName, "vectors"); } } else { vectorsName = new char[strlen(this->VectorsName) * 4 + 1]; this->EncodeString(vectorsName, this->VectorsName, true); } char format[1024]; snprintf(format, sizeof(format), "%s %s\n", vectorsName, "%s"); delete[] vectorsName; return this->WriteArray(fp, vectors->GetDataType(), vectors, format, num, 3); } int vtkDataWriter::WriteNormalData(ostream* fp, vtkDataArray* normals, vtkIdType num) { char* normalsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->NormalsName) { if (normals->GetName() && strlen(normals->GetName())) { normalsName = new char[strlen(normals->GetName()) * 4 + 1]; this->EncodeString(normalsName, normals->GetName(), true); } else { normalsName = new char[strlen("normals") + 1]; strcpy(normalsName, "normals"); } } else { normalsName = new char[strlen(this->NormalsName) * 4 + 1]; this->EncodeString(normalsName, this->NormalsName, true); } *fp << "NORMALS "; char format[1024]; snprintf(format, sizeof(format), "%s %s\n", normalsName, "%s"); delete[] normalsName; return this->WriteArray(fp, normals->GetDataType(), normals, format, num, 3); } //------------------------------------------------------------------------------ int vtkDataWriter::WriteTCoordData(ostream* fp, vtkDataArray* tcoords, vtkIdType num) { int dim = tcoords->GetNumberOfComponents(); char* tcoordsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->TCoordsName) { if (tcoords->GetName() && strlen(tcoords->GetName())) { tcoordsName = new char[strlen(tcoords->GetName()) * 4 + 1]; this->EncodeString(tcoordsName, tcoords->GetName(), true); } else { tcoordsName = new char[strlen("tcoords") + 1]; strcpy(tcoordsName, "tcoords"); } } else { tcoordsName = new char[strlen(this->TCoordsName) * 4 + 1]; this->EncodeString(tcoordsName, this->TCoordsName, true); } *fp << "TEXTURE_COORDINATES "; char format[1024]; snprintf(format, sizeof(format), "%s %d %s\n", tcoordsName, dim, "%s"); delete[] tcoordsName; return this->WriteArray(fp, tcoords->GetDataType(), tcoords, format, num, dim); } //------------------------------------------------------------------------------ int vtkDataWriter::WriteTensorData(ostream* fp, vtkDataArray* tensors, vtkIdType num) { char* tensorsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->TensorsName) { if (tensors->GetName() && strlen(tensors->GetName())) { tensorsName = new char[strlen(tensors->GetName()) * 4 + 1]; this->EncodeString(tensorsName, tensors->GetName(), true); } else { tensorsName = new char[strlen("tensors") + 1]; strcpy(tensorsName, "tensors"); } } else { tensorsName = new char[strlen(this->TensorsName) * 4 + 1]; this->EncodeString(tensorsName, this->TensorsName, true); } *fp << "TENSORS"; int numComp = 9; if (tensors->GetNumberOfComponents() == 6) { *fp << "6"; numComp = 6; } *fp << " "; char format[1024]; snprintf(format, sizeof(format), "%s %s\n", tensorsName, "%s"); delete[] tensorsName; return this->WriteArray(fp, tensors->GetDataType(), tensors, format, num, numComp); } //------------------------------------------------------------------------------ int vtkDataWriter::WriteGlobalIdData(ostream* fp, vtkDataArray* globalIds, vtkIdType num) { *fp << "GLOBAL_IDS "; char* globalIdsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->GlobalIdsName) { if (globalIds->GetName() && strlen(globalIds->GetName())) { globalIdsName = new char[strlen(globalIds->GetName()) * 4 + 1]; this->EncodeString(globalIdsName, globalIds->GetName(), true); } else { globalIdsName = new char[strlen("global_ids") + 1]; strcpy(globalIdsName, "global_ids"); } } else { globalIdsName = new char[strlen(this->GlobalIdsName) * 4 + 1]; this->EncodeString(globalIdsName, this->GlobalIdsName, true); } char format[1024]; snprintf(format, sizeof(format), "%s %s\n", globalIdsName, "%s"); delete[] globalIdsName; return this->WriteArray(fp, globalIds->GetDataType(), globalIds, format, num, 1); } //------------------------------------------------------------------------------ int vtkDataWriter::WritePedigreeIdData(ostream* fp, vtkAbstractArray* pedigreeIds, vtkIdType num) { *fp << "PEDIGREE_IDS "; char* pedigreeIdsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->PedigreeIdsName) { if (pedigreeIds->GetName() && strlen(pedigreeIds->GetName())) { pedigreeIdsName = new char[strlen(pedigreeIds->GetName()) * 4 + 1]; this->EncodeString(pedigreeIdsName, pedigreeIds->GetName(), true); } else { pedigreeIdsName = new char[strlen("pedigree_ids") + 1]; strcpy(pedigreeIdsName, "pedigree_ids"); } } else { pedigreeIdsName = new char[strlen(this->PedigreeIdsName) * 4 + 1]; this->EncodeString(pedigreeIdsName, this->PedigreeIdsName, true); } char format[1024]; snprintf(format, sizeof(format), "%s %s\n", pedigreeIdsName, "%s"); delete[] pedigreeIdsName; return this->WriteArray(fp, pedigreeIds->GetDataType(), pedigreeIds, format, num, 1); } //------------------------------------------------------------------------------ int vtkDataWriter::WriteEdgeFlagsData(ostream* fp, vtkDataArray* edgeFlags, vtkIdType num) { *fp << "EDGE_FLAGS "; char* edgeFlagsName; // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. if (!this->EdgeFlagsName) { if (edgeFlags->GetName() && strlen(edgeFlags->GetName())) { edgeFlagsName = new char[strlen(edgeFlags->GetName()) * 4 + 1]; this->EncodeString(edgeFlagsName, edgeFlags->GetName(), true); } else { edgeFlagsName = new char[strlen("edge_flags") + 1]; strcpy(edgeFlagsName, "edge_flags"); } } else { edgeFlagsName = new char[strlen(this->EdgeFlagsName) * 4 + 1]; this->EncodeString(edgeFlagsName, this->EdgeFlagsName, true); } char format[1024]; snprintf(format, sizeof(format), "%s %s\n", edgeFlagsName, "%s"); delete[] edgeFlagsName; return this->WriteArray(fp, edgeFlags->GetDataType(), edgeFlags, format, num, 1); } //------------------------------------------------------------------------------ bool vtkDataWriter::CanWriteInformationKey(vtkInformation* info, vtkInformationKey* key) { vtkInformationDoubleKey* dKey = nullptr; vtkInformationDoubleVectorKey* dvKey = nullptr; if ((dKey = vtkInformationDoubleKey::SafeDownCast(key))) { // Skip keys with NaNs/infs double value = info->Get(dKey); if (!vtkMath::IsFinite(value)) { vtkWarningMacro("Skipping key '" << key->GetLocation() << "::" << key->GetName() << "': bad value: " << value); return false; } return true; } else if ((dvKey = vtkInformationDoubleVectorKey::SafeDownCast(key))) { // Skip keys with NaNs/infs int length = dvKey->Length(info); bool valid = true; for (int i = 0; i < length; ++i) { double value = info->Get(dvKey, i); if (!vtkMath::IsFinite(value)) { vtkWarningMacro("Skipping key '" << key->GetLocation() << "::" << key->GetName() << "': bad value: " << value); valid = false; break; } } return valid; } else if (vtkInformationIdTypeKey::SafeDownCast(key) || vtkInformationIntegerKey::SafeDownCast(key) || vtkInformationIntegerVectorKey::SafeDownCast(key) || vtkInformationStringKey::SafeDownCast(key) || vtkInformationStringVectorKey::SafeDownCast(key) || vtkInformationUnsignedLongKey::SafeDownCast(key)) { return true; } vtkDebugMacro("Could not serialize information with key " << key->GetLocation() << "::" << key->GetName() << ": " "Unsupported data type '" << key->GetClassName() << "'."); return false; } //------------------------------------------------------------------------------ namespace { void writeInfoHeader(std::ostream* fp, vtkInformationKey* key) { *fp << "NAME " << key->GetName() << " LOCATION " << key->GetLocation() << "\n" << "DATA "; } } // end anon namespace int vtkDataWriter::WriteInformation(std::ostream* fp, vtkInformation* info) { // This will contain the serializable keys: vtkNew keys; vtkInformationKey* key = nullptr; vtkNew iter; iter->SetInformationWeak(info); for (iter->InitTraversal(); (key = iter->GetCurrentKey()); iter->GoToNextItem()) { if (this->CanWriteInformationKey(info, key)) { keys->CopyEntry(info, key); } } *fp << "INFORMATION " << keys->GetNumberOfKeys() << "\n"; iter->SetInformationWeak(keys); char buffer[1024]; for (iter->InitTraversal(); (key = iter->GetCurrentKey()); iter->GoToNextItem()) { vtkInformationDoubleKey* dKey = nullptr; vtkInformationDoubleVectorKey* dvKey = nullptr; vtkInformationIdTypeKey* idKey = nullptr; vtkInformationIntegerKey* iKey = nullptr; vtkInformationIntegerVectorKey* ivKey = nullptr; vtkInformationStringKey* sKey = nullptr; vtkInformationStringVectorKey* svKey = nullptr; vtkInformationUnsignedLongKey* ulKey = nullptr; if ((dKey = vtkInformationDoubleKey::SafeDownCast(key))) { writeInfoHeader(fp, key); // "%lg" is used to write double array data in ascii, using the same // precision here. snprintf(buffer, sizeof(buffer), "%lg", dKey->Get(info)); *fp << buffer << "\n"; } else if ((dvKey = vtkInformationDoubleVectorKey::SafeDownCast(key))) { writeInfoHeader(fp, key); // Size first: int length = dvKey->Length(info); snprintf(buffer, sizeof(buffer), "%d", length); *fp << buffer << " "; double* data = dvKey->Get(info); for (int i = 0; i < length; ++i) { // "%lg" is used to write double array data in ascii, using the same // precision here. snprintf(buffer, sizeof(buffer), "%lg", data[i]); *fp << buffer << " "; } *fp << "\n"; } else if ((idKey = vtkInformationIdTypeKey::SafeDownCast(key))) { writeInfoHeader(fp, key); snprintf(buffer, sizeof(buffer), vtkTypeTraits::ParseFormat(), idKey->Get(info)); *fp << buffer << "\n"; } else if ((iKey = vtkInformationIntegerKey::SafeDownCast(key))) { writeInfoHeader(fp, key); snprintf(buffer, sizeof(buffer), vtkTypeTraits::ParseFormat(), iKey->Get(info)); *fp << buffer << "\n"; } else if ((ivKey = vtkInformationIntegerVectorKey::SafeDownCast(key))) { writeInfoHeader(fp, key); // Size first: int length = ivKey->Length(info); snprintf(buffer, sizeof(buffer), "%d", length); *fp << buffer << " "; int* data = ivKey->Get(info); for (int i = 0; i < length; ++i) { snprintf(buffer, sizeof(buffer), vtkTypeTraits::ParseFormat(), data[i]); *fp << buffer << " "; } *fp << "\n"; } else if ((sKey = vtkInformationStringKey::SafeDownCast(key))) { writeInfoHeader(fp, key); this->EncodeWriteString(fp, sKey->Get(info), false); *fp << "\n"; } else if ((svKey = vtkInformationStringVectorKey::SafeDownCast(key))) { writeInfoHeader(fp, key); // Size first: int length = svKey->Length(info); snprintf(buffer, sizeof(buffer), "%d", length); *fp << buffer << "\n"; for (int i = 0; i < length; ++i) { this->EncodeWriteString(fp, svKey->Get(info, i), false); *fp << "\n"; } } else if ((ulKey = vtkInformationUnsignedLongKey::SafeDownCast(key))) { writeInfoHeader(fp, key); snprintf( buffer, sizeof(buffer), vtkTypeTraits::ParseFormat(), ulKey->Get(info)); *fp << buffer << "\n"; } else { vtkDebugMacro("Could not serialize information with key " << key->GetLocation() << "::" << key->GetName() << ": " "Unsupported data type '" << key->GetClassName() << "'."); } } return 1; } //------------------------------------------------------------------------------ static int vtkIsInTheList(int index, int* list, vtkIdType numElem) { for (vtkIdType i = 0; i < numElem; i++) { if (index == list[i]) { return 1; } } return 0; } //------------------------------------------------------------------------------ int vtkDataWriter::WriteFieldData(ostream* fp, vtkFieldData* f) { char format[1024]; int i, numArrays = f->GetNumberOfArrays(), actNumArrays = 0; vtkIdType numComp, numTuples; int attributeIndices[vtkDataSetAttributes::NUM_ATTRIBUTES]; vtkAbstractArray* array; for (i = 0; i < vtkDataSetAttributes::NUM_ATTRIBUTES; i++) { attributeIndices[i] = -1; } vtkDataSetAttributes* dsa; if ((dsa = vtkDataSetAttributes::SafeDownCast(f))) { dsa->GetAttributeIndices(attributeIndices); } for (i = 0; i < numArrays; i++) { if (!vtkIsInTheList(i, attributeIndices, vtkDataSetAttributes::NUM_ATTRIBUTES)) { actNumArrays++; } } if (actNumArrays < 1) { return 1; } *fp << "FIELD " << this->FieldDataName << " " << actNumArrays << "\n"; for (i = 0; i < numArrays; i++) { if (!vtkIsInTheList(i, attributeIndices, vtkDataSetAttributes::NUM_ATTRIBUTES)) { array = f->GetAbstractArray(i); if (array != nullptr) { numComp = array->GetNumberOfComponents(); numTuples = array->GetNumberOfTuples(); // Buffer size is size of array name times four because // in theory there could be array name consisting of only // weird symbols. char* buffer; if (!array->GetName() || strlen(array->GetName()) == 0) { buffer = strcpy(new char[strlen("unknown") + 1], "unknown"); } else { buffer = new char[strlen(array->GetName()) * 4 + 1]; this->EncodeString(buffer, array->GetName(), true); } snprintf(format, sizeof(format), "%s %" VTK_ID_TYPE_PRId " %" VTK_ID_TYPE_PRId " %s\n", buffer, numComp, numTuples, "%s"); this->WriteArray(fp, array->GetDataType(), array, format, numTuples, numComp); delete[] buffer; } else { *fp << "NULL_ARRAY" << endl; } } } if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return 0; } return 1; } //------------------------------------------------------------------------------ int vtkDataWriter::WriteCellsLegacy(ostream* fp, vtkCellArray* cells, const char* label) { if (!cells || cells->GetNumberOfCells() < 1) { return 1; } int ncells = cells->GetNumberOfCells(); int size = cells->GetNumberOfConnectivityEntries(); if (ncells < 1) { return 1; } *fp << label << " " << ncells << " " << size << "\n"; // Use cell array iterator to convert new VTK cell data array // into form that can be readily output in legacy format. auto iter = vtk::TakeSmartPointer(cells->NewIterator()); const vtkIdType* pts = nullptr; vtkIdType npts = 0; if (this->FileType == VTK_ASCII) { for (iter->GoToFirstCell(); !iter->IsDoneWithTraversal(); iter->GoToNextCell()) { iter->GetCurrentCell(npts, pts); *fp << static_cast(npts) << " "; for (auto i = 0; i < npts; i++) { // currently writing vtkIdType as int *fp << static_cast(pts[i]) << " "; } *fp << "\n"; } } // ASCII Type else { // swap the bytes if necessary // currently writing vtkIdType as int int arraySize = cells->GetNumberOfConnectivityEntries(); int* intArray = new int[arraySize]; int* intArrayPtr = intArray; for (iter->GoToFirstCell(); !iter->IsDoneWithTraversal(); iter->GoToNextCell()) { iter->GetCurrentCell(npts, pts); *intArrayPtr++ = npts; for (auto i = 0; i < npts; ++i) { *intArrayPtr++ = pts[i]; } } vtkByteSwap::SwapWrite4BERange(intArray, size, fp); delete[] intArray; } // BINARY Type *fp << "\n"; fp->flush(); if (fp->fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return 0; } return 1; } //------------------------------------------------------------------------------ int vtkDataWriter::WriteCells(ostream* fp, vtkCellArray* cells, const char* label) { // Shunt to legacy if needed if (this->FileVersion == VTK_LEGACY_READER_VERSION_4_2) { return this->WriteCellsLegacy(fp, cells, label); } // Okay, the latest and greatest format if (!cells || cells->GetNumberOfCells() < 1) { return 1; } vtkIdType offsetsSize = cells->GetNumberOfOffsets(); vtkIdType connSize = cells->GetNumberOfConnectivityIds(); bool is64Bit = cells->IsStorage64Bit(); int type = is64Bit ? VTK_TYPE_INT64 : VTK_TYPE_INT32; *fp << label << " " << offsetsSize << " " << connSize << "\n"; this->WriteArray(fp, type, cells->GetOffsetsArray(), "OFFSETS %s\n", offsetsSize, 1); this->WriteArray(fp, type, cells->GetConnectivityArray(), "CONNECTIVITY %s\n", connSize, 1); fp->flush(); if (fp->fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return 0; } return 1; } //------------------------------------------------------------------------------ void vtkDataWriter::WriteData() { vtkErrorMacro(<< "WriteData() should be implemented in concrete subclass"); } //------------------------------------------------------------------------------ // Close a vtk file. void vtkDataWriter::CloseVTKFile(ostream* fp) { vtkDebugMacro(<< "Closing vtk file\n"); // Restore the previous locale settings std::locale::global(this->CurrentLocale); if (fp != nullptr) { if (this->WriteToOutputString) { std::ostringstream* ostr = static_cast(fp); delete[] this->OutputString; const size_t strlength = ostr->str().size(); if (strlength > static_cast(vtkTypeTraits::Max())) { this->OutputString = nullptr; this->OutputStringLength = 0; vtkErrorMacro("OutputStringLength overflow: the length of data in the " "writer is greater than what would fit in a variable of type " "`vtkIdType`. You may have to recompile with VTK_USE_64BIT_IDS." "Presently, vtkIdType is " << sizeof(vtkIdType) * 8 << " bits."); } else { this->OutputStringLength = static_cast(strlength); this->OutputString = new char[strlength + 1]; } memcpy(this->OutputString, ostr->str().c_str(), this->OutputStringLength + 1); } delete fp; } } //------------------------------------------------------------------------------ char* vtkDataWriter::RegisterAndGetOutputString() { char* tmp = this->OutputString; this->OutputString = nullptr; this->OutputStringLength = 0; return tmp; } //------------------------------------------------------------------------------ vtkStdString vtkDataWriter::GetOutputStdString() { return vtkStdString(this->OutputString, this->OutputStringLength); } //------------------------------------------------------------------------------ void vtkDataWriter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "File Name: " << (this->FileName ? this->FileName : "(none)") << "\n"; os << indent << "File Version: " << this->FileVersion << "\n"; if (this->FileType == VTK_BINARY) { os << indent << "File Type: BINARY\n"; } else { os << indent << "File Type: ASCII\n"; } if (this->Header) { os << indent << "Header: " << this->Header << "\n"; } else { os << indent << "Header: (None)\n"; } os << indent << "Output String Length: " << this->OutputStringLength << "\n"; os << indent << "Output String (addr): " << static_cast(this->OutputString) << "\n"; os << indent << "WriteToOutputString: " << (this->WriteToOutputString ? "On\n" : "Off\n"); if (this->ScalarsName) { os << indent << "Scalars Name: " << this->ScalarsName << "\n"; } else { os << indent << "Scalars Name: (None)\n"; } if (this->VectorsName) { os << indent << "Vectors Name: " << this->VectorsName << "\n"; } else { os << indent << "Vectors Name: (None)\n"; } if (this->NormalsName) { os << indent << "Normals Name: " << this->NormalsName << "\n"; } else { os << indent << "Normals Name: (None)\n"; } if (this->TensorsName) { os << indent << "Tensors Name: " << this->TensorsName << "\n"; } else { os << indent << "Tensors Name: (None)\n"; } if (this->TCoordsName) { os << indent << "Texture Coords Name: " << this->TCoordsName << "\n"; } else { os << indent << "Texture Coordinates Name: (None)\n"; } if (this->GlobalIdsName) { os << indent << "Global Ids Name: " << this->GlobalIdsName << "\n"; } else { os << indent << "Global Ids Name: (None)\n"; } if (this->PedigreeIdsName) { os << indent << "Pedigree Ids Name: " << this->PedigreeIdsName << "\n"; } else { os << indent << "Pedigree Ids Name: (None)\n"; } if (this->EdgeFlagsName) { os << indent << "Edge Flags Name: " << this->EdgeFlagsName << "\n"; } else { os << indent << "Edge Flags Name: (None)\n"; } if (this->LookupTableName) { os << indent << "Lookup Table Name: " << this->LookupTableName << "\n"; } else { os << indent << "Lookup Table Name: (None)\n"; } if (this->FieldDataName) { os << indent << "Field Data Name: " << this->FieldDataName << "\n"; } else { os << indent << "Field Data Name: (None)\n"; } } //------------------------------------------------------------------------------ int vtkDataWriter::WriteDataSetData(ostream* fp, vtkDataSet* ds) { vtkFieldData* field = ds->GetFieldData(); if (field && field->GetNumberOfTuples() > 0) { if (!this->WriteFieldData(fp, field)) { return 0; // we tried to write field data, but we couldn't } } return 1; }