/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkCommunicator.cxx,v $ 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 "vtkCommunicator.h" #include "vtkCharArray.h" #include "vtkDataSetReader.h" #include "vtkDataSetWriter.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkIdTypeArray.h" #include "vtkImageClip.h" #include "vtkIntArray.h" #include "vtkStructuredPoints.h" #include "vtkStructuredPointsReader.h" #include "vtkStructuredPointsWriter.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedLongArray.h" vtkCxxRevisionMacro(vtkCommunicator, "$Revision: 1.28 $"); template int SendDataArray(T* data, int length, int handle, int tag, vtkCommunicator *self) { self->Send(data, length, handle, tag); return 1; } vtkCommunicator::vtkCommunicator() { this->MarshalString = 0; this->MarshalStringLength = 0; this->MarshalDataLength = 0; } vtkCommunicator::~vtkCommunicator() { this->DeleteAndSetMarshalString(0, 0); } int vtkCommunicator::UseCopy = 0; void vtkCommunicator::SetUseCopy(int useCopy) { vtkCommunicator::UseCopy = useCopy; } void vtkCommunicator::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Marshal string: "; if ( this->MarshalString ) { os << this->MarshalString << endl; } else { os << "(None)" << endl; } os << indent << "Marshal string length: " << this->MarshalStringLength << endl; os << indent << "Marshal data length: " << this->MarshalDataLength << endl; } //---------------------------------------------------------------------------- // Internal method. Assumes responsibility for deleting the string void vtkCommunicator::DeleteAndSetMarshalString(char *str, int strLength) { // delete any previous string if (this->MarshalString) { delete [] this->MarshalString; this->MarshalString = 0; this->MarshalStringLength = 0; this->MarshalDataLength = 0; } this->MarshalString = str; this->MarshalStringLength = strLength; } // Need to add better error checking int vtkCommunicator::Send(vtkDataObject* data, int remoteHandle, int tag) { if (data == NULL) { this->MarshalDataLength = 0; this->Send( &this->MarshalDataLength, 1, remoteHandle, tag); return 1; } if (this->WriteObject(data)) { this->Send( &this->MarshalDataLength, 1, remoteHandle, tag); // then send the string. this->Send( this->MarshalString, this->MarshalDataLength, remoteHandle, tag); return 1; } // could not marshal data return 0; } int vtkCommunicator::Send(vtkDataArray* data, int remoteHandle, int tag) { int type = -1; if (data == NULL) { this->MarshalDataLength = 0; this->Send( &type, 1, remoteHandle, tag); return 1; } // send array type type = data->GetDataType(); this->Send( &type, 1, remoteHandle, tag); // send array size vtkIdType size = data->GetSize(); this->Send( &size, 1, remoteHandle, tag); // send number of components in array int numComponents = data->GetNumberOfComponents(); this->Send( &numComponents, 1, remoteHandle, tag); const char* name = data->GetName(); int len = 0; if (name) { len = static_cast(strlen(name)) + 1; } // send length of name this->Send( &len, 1, remoteHandle, tag); if (len > 0) { // send name this->Send( const_cast(name), len, remoteHandle, tag); } // now send the raw array switch (type) { case VTK_CHAR: return SendDataArray(static_cast(data->GetVoidPointer(0)), size, remoteHandle, tag, this); case VTK_UNSIGNED_CHAR: return SendDataArray(static_cast(data->GetVoidPointer(0)), size, remoteHandle, tag, this); case VTK_INT: return SendDataArray(static_cast(data->GetVoidPointer(0)), size, remoteHandle, tag, this); case VTK_UNSIGNED_LONG: return SendDataArray(static_cast(data->GetVoidPointer(0)), size, remoteHandle, tag, this); case VTK_FLOAT: return SendDataArray(static_cast(data->GetVoidPointer(0)), size, remoteHandle, tag, this); case VTK_DOUBLE: return SendDataArray(static_cast(data->GetVoidPointer(0)), size, remoteHandle, tag, this); case VTK_ID_TYPE: return SendDataArray(static_cast(data->GetVoidPointer(0)), size, remoteHandle, tag, this); default: vtkErrorMacro(<<"Unsupported data type!"); return 0; // could not marshal data } } int vtkCommunicator::Receive(vtkDataObject* data, int remoteHandle, int tag) { int dataLength; // First receive the data length. if (!this->Receive( &dataLength, 1, remoteHandle, tag)) { vtkErrorMacro("Could not receive data!"); return 0; } if (dataLength < 0) { vtkErrorMacro("Bad data length"); return 0; } if (dataLength == 0) { // This indicates a NULL object was sent. Do nothing. return 1; } // if we cannot reuse the string, allocate a new one. if (dataLength > this->MarshalStringLength) { char *str = new char[dataLength + 10]; // maybe a little extra? this->DeleteAndSetMarshalString(str, dataLength + 10); } // Receive the string this->Receive(this->MarshalString, dataLength, remoteHandle, tag); this->MarshalDataLength = dataLength; this->ReadObject(data); // we should really look at status to determine success return 1; } int vtkCommunicator::Receive(vtkDataArray* data, int remoteHandle, int tag) { vtkIdType size; int type; int numComponents; int nameLength; char *c = 0; unsigned char *uc = 0; int *i = 0; unsigned long *ul = 0; float *f = 0; double *d = 0; vtkIdType *idt = 0; // First receive the data type. if (!this->Receive( &type, 1, remoteHandle, tag)) { vtkErrorMacro("Could not receive data!"); return 0; } if (type == -1) { // This indicates a NULL object was sent. Do nothing. return 1; } // Next receive the data length. if (!this->Receive( &size, 1, remoteHandle, tag)) { vtkErrorMacro("Could not receive data!"); return 0; } // Next receive the number of components. this->Receive( &numComponents, 1, remoteHandle, tag); // Next receive the length of the name. this->Receive( &nameLength, 1, remoteHandle, tag); if ( nameLength > 0 ) { char *str = new char[nameLength]; this->DeleteAndSetMarshalString(str, nameLength); // Receive the name this->Receive(this->MarshalString, nameLength, remoteHandle, tag); this->MarshalDataLength = nameLength; } if (size < 0) { vtkErrorMacro("Bad data length"); return 0; } if (size == 0) { // This indicates a NULL object was sent. Do nothing. return 1; } // Receive the raw data array switch (type) { case VTK_CHAR: c = new char[size]; this->Receive(c, size, remoteHandle, tag); static_cast(data)->SetArray(c, size, 0); break; case VTK_UNSIGNED_CHAR: uc = new unsigned char[size]; this->Receive(uc, size, remoteHandle, tag); static_cast(data)->SetArray(uc, size, 0); break; case VTK_INT: i = new int[size]; this->Receive(i, size, remoteHandle, tag); static_cast(data)->SetArray(i, size, 0); break; case VTK_UNSIGNED_LONG: ul = new unsigned long[size]; this->Receive(ul, size, remoteHandle, tag); static_cast(data)->SetArray(ul, size, 0); break; case VTK_FLOAT: f = new float[size]; this->Receive(f, size, remoteHandle, tag); static_cast(data)->SetArray(f, size, 0); break; case VTK_DOUBLE: d = new double[size]; this->Receive(d, size, remoteHandle, tag); static_cast(data)->SetArray(d, size, 0); break; case VTK_ID_TYPE: idt = new vtkIdType[size]; this->Receive(idt, size, remoteHandle, tag); static_cast(data)->SetArray(idt, size, 0); break; default: vtkErrorMacro(<<"Unsupported data type!"); return 0; // could not marshal data } if (nameLength > 0) { data->SetName(this->MarshalString); } else { data->SetName(0); } data->SetNumberOfComponents(numComponents); return 1; } int vtkCommunicator::WriteObject(vtkDataObject *data) { if (strcmp(data->GetClassName(), "vtkPolyData") == 0 || strcmp(data->GetClassName(), "vtkUnstructuredGrid") == 0 || strcmp(data->GetClassName(), "vtkStructuredGrid") == 0 || strcmp(data->GetClassName(), "vtkRectilinearGrid") == 0 || strcmp(data->GetClassName(), "vtkStructuredPoints") == 0) { return this->WriteDataSet((vtkDataSet*)data); } if (strcmp(data->GetClassName(), "vtkImageData") == 0) { return this->WriteImageData((vtkImageData*)data); } vtkErrorMacro("Cannot marshal object of type " << data->GetClassName()); return 0; } int vtkCommunicator::ReadObject(vtkDataObject *data) { if (strcmp(data->GetClassName(), "vtkPolyData") == 0 || strcmp(data->GetClassName(), "vtkUnstructuredGrid") == 0 || strcmp(data->GetClassName(), "vtkStructuredGrid") == 0 || strcmp(data->GetClassName(), "vtkRectilinearGrid") == 0 || strcmp(data->GetClassName(), "vtkStructuredPoints") == 0) { return this->ReadDataSet((vtkDataSet*)data); } if (strcmp(data->GetClassName(), "vtkImageData") == 0) { return this->ReadImageData((vtkImageData*)data); } vtkErrorMacro("Cannot marshal object of type " << data->GetClassName()); return 1; } int vtkCommunicator::WriteImageData(vtkImageData *data) { vtkImageClip *clip; vtkStructuredPointsWriter *writer; int size; // keep Update from propagating vtkImageData *tmp = vtkImageData::New(); tmp->ShallowCopy(data); clip = vtkImageClip::New(); clip->SetInput(tmp); clip->SetOutputWholeExtent(data->GetExtent()); writer = vtkStructuredPointsWriter::New(); writer->SetFileTypeToBinary(); writer->WriteToOutputStringOn(); writer->SetInput(clip->GetOutput()); writer->Write(); size = writer->GetOutputStringLength(); this->DeleteAndSetMarshalString(writer->RegisterAndGetOutputString(), size); this->MarshalDataLength = size; clip->Delete(); writer->Delete(); tmp->Delete(); return 1; } int vtkCommunicator::ReadImageData(vtkImageData *object) { vtkStructuredPointsReader *reader = vtkStructuredPointsReader::New(); if (this->MarshalString == NULL || this->MarshalStringLength <= 0) { return 0; } reader->ReadFromInputStringOn(); vtkCharArray* mystring = vtkCharArray::New(); // mystring should not delete the string when it's done, // that's our job. mystring->SetArray(this->MarshalString, this->MarshalDataLength, 1); reader->SetInputArray(mystring); mystring->Delete(); reader->GetOutput()->Update(); object->ShallowCopy(reader->GetOutput()); reader->Delete(); return 1; } int vtkCommunicator::WriteDataSet(vtkDataSet *data) { vtkDataSet *copy; unsigned long size; vtkDataSetWriter *writer = vtkDataSetWriter::New(); copy = data->NewInstance(); copy->ShallowCopy(data); // There is a problem with binary files with no data. if (copy->GetNumberOfCells() + copy->GetNumberOfPoints() > 0) { writer->SetFileTypeToBinary(); } writer->WriteToOutputStringOn(); writer->SetInput(copy); writer->Write(); size = writer->GetOutputStringLength(); this->DeleteAndSetMarshalString(writer->RegisterAndGetOutputString(), size); this->MarshalDataLength = size; writer->Delete(); copy->Delete(); return 1; } int vtkCommunicator::ReadDataSet(vtkDataSet *object) { vtkDataSetReader *reader = vtkDataSetReader::New(); if (this->MarshalString == NULL || this->MarshalStringLength <= 0) { return 0; } reader->ReadFromInputStringOn(); vtkCharArray* mystring = vtkCharArray::New(); // mystring should not delete the string when it's done, // that's our job. mystring->SetArray(this->MarshalString, this->MarshalDataLength, 1); reader->SetInputArray(mystring); mystring->Delete(); reader->Update(); object->ShallowCopy(reader->GetOutput()); reader->Delete(); return 1; }