3#include <vtkInformation.h>
5#include <vtkImageData.h>
6#include <vtkMultiBlockDataSet.h>
7#include <vtkPolyData.h>
8#include <vtkSmartPointer.h>
9#include <vtkStringArray.h>
10#include <vtkUnstructuredGrid.h>
12#include <vtkCellData.h>
13#include <vtkDoubleArray.h>
14#include <vtkPointData.h>
15#include <vtkUnsignedCharArray.h>
17#include <vtkCellArray.h>
20#include <boost/algorithm/string/replace.hpp>
21#include <boost/lexical_cast.hpp>
22#include <boost/optional/optional.hpp>
23#include <boost/property_tree/json_parser.hpp>
24#include <boost/property_tree/ptree.hpp>
34 this->SetNumberOfInputPorts(1);
35 this->SetNumberOfOutputPorts(1);
42 info->Remove(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE());
44 vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(),
"vtkMultiBlockDataSet");
45 info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(),
"vtkDataSet");
53 info->Set(vtkDataObject::DATA_TYPE_NAME(),
"vtkMultiBlockDataSet");
60 vtkInformationVector **inputVector,
61 vtkInformationVector *outputVector) {
72 }
catch(
const std::exception &e) {
73 this->
printErr(
"Unable to start server:\n" + std::string(e.what()));
80 auto output = vtkMultiBlockDataSet::GetData(outputVector);
81 output->ShallowCopy(this->LastOutput);
85 auto input = vtkDataObject::GetData(inputVector[0]);
88 this->LastInput->ShallowCopy(input);
89 if(!this->
processEvent(
"on_message",
"RequestInputVtkDataSet"))
96 const std::string &eventData) {
97 if(eventData.compare(
"RequestInputVtkDataSet") == 0) {
100 }
else if(eventData.rfind(
"{\"vtkDataSet", 12) == 0) {
105 return WebSocketIO::processEvent(eventName, eventData);
110 const boost::property_tree::ptree::key_type &key) {
111 return pt.get_child(key).get_value<T>();
116 const boost::property_tree::ptree::key_type &key,
118 std::vector<double> values;
120 jsonGetValue<std::string>(pt, key), values);
122 for(
size_t i = 0, j = values.size(); i < j; i++) {
123 result[i] = (T)values[i];
127static bool jsonHasChild(
const boost::property_tree::ptree &pt,
128 const boost::property_tree::ptree::key_type &key) {
129 return pt.find(key) != pt.not_found();
134 this->
printMsg(
"Parsing vtkDataObject from JSON string", 0, 0,
140 boost::property_tree::ptree pt;
142 std::stringstream ss;
144 boost::property_tree::read_json(ss, pt);
145 }
catch(
const std::exception &e) {
146 this->
printErr(
"Unable to parse JSON message: " + json);
153 for(
auto it = pt.begin(); it != pt.end(); ++it) {
156 auto jsonVtkDataSet = it->second;
157 if(!jsonHasChild(jsonVtkDataSet,
"className")
158 || !jsonHasChild(jsonVtkDataSet,
"points")
159 || !jsonHasChild(jsonVtkDataSet,
"cells")
160 || !jsonHasChild(jsonVtkDataSet,
"pointData")
161 || !jsonHasChild(jsonVtkDataSet,
"cellData")
162 || !jsonHasChild(jsonVtkDataSet,
"fieldData")) {
163 this->
printErr(
"Invalid vtkDataSet serialization.");
167 if(jsonGetValue<std::string>(jsonVtkDataSet,
"className")
168 .compare(
"vtkUnstructuredGrid")
171 "Currently WebSocketIO only supports parsing 'vtkUnstructuredGrids'.");
178 = jsonGetValue<int>(jsonVtkDataSet,
"points.coordinates.nTuples");
181 points->SetNumberOfPoints(nPoints);
183 jsonArrayToArray<float>(jsonVtkDataSet,
"points.coordinates.data",
186 block->SetPoints(points);
192 constexpr int vtkCellsTypeHash[20] = {VTK_EMPTY_CELL,
197 VTK_CONVEX_POINT_SET,
198 VTK_CONVEX_POINT_SET,
199 VTK_CONVEX_POINT_SET,
201 VTK_CONVEX_POINT_SET,
202 VTK_CONVEX_POINT_SET,
203 VTK_CONVEX_POINT_SET,
204 VTK_CONVEX_POINT_SET,
205 VTK_CONVEX_POINT_SET,
206 VTK_CONVEX_POINT_SET,
207 VTK_CONVEX_POINT_SET,
208 VTK_CONVEX_POINT_SET,
209 VTK_CONVEX_POINT_SET,
210 VTK_CONVEX_POINT_SET,
211 VTK_CONVEX_POINT_SET};
214 = jsonGetValue<int>(jsonVtkDataSet,
"cells.offsetsArray.nTuples");
216 offsets->SetNumberOfTuples(nOffsets);
218 jsonArrayToArray<vtkIdType>(
219 jsonVtkDataSet,
"cells.offsetsArray.data", offsetsData);
222 = jsonGetValue<int>(jsonVtkDataSet,
"cells.connectivityArray.nTuples");
224 connectivity->SetNumberOfTuples(nConnectivity);
225 jsonArrayToArray<vtkIdType>(
226 jsonVtkDataSet,
"cells.connectivityArray.data",
230 cells->SetData(offsets, connectivity);
233 cellTypes->SetNumberOfTuples(nOffsets - 1);
235 for(
int i = 1; i < nOffsets; i++) {
237 = vtkCellsTypeHash[offsetsData[i] - offsetsData[i - 1]];
240 block->SetCells(cellTypes, cells);
243 auto addArraysToAssociation = [](vtkFieldData *fd,
244 const boost::property_tree::ptree &fdJSON,
245 const std::string &fdKey) {
247 for(
const auto &pda : fdJSON.get_child(fdKey)) {
248 const auto &jsonArray = pda.second;
249 size_t nComponents = jsonGetValue<size_t>(jsonArray,
"nComponents");
250 size_t nTuples = jsonGetValue<size_t>(jsonArray,
"nTuples");
253 vtkDataArray::CreateArray(jsonGetValue<int>(jsonArray,
"dataType")));
255 array->SetName(jsonGetValue<std::string>(jsonArray,
"name").data());
256 array->SetNumberOfComponents(nComponents);
257 array->SetNumberOfTuples(nTuples);
259 if(
auto dataArray = vtkDataArray::SafeDownCast(array)) {
260 switch(dataArray->GetDataType()) {
261 vtkTemplateMacro(jsonArrayToArray<VTK_TT>(
265 }
else if(
auto stringArray = vtkStringArray::SafeDownCast(array)) {
266 std::vector<std::string> values;
268 jsonGetValue<std::string>(jsonArray,
"data"), values);
270 for(
size_t i = 0; i < values.size(); i++)
271 stringArray->SetValue(i, values[i]);
281 if(!addArraysToAssociation(
282 block->GetPointData(), jsonVtkDataSet,
"pointData")) {
283 this->
printErr(
"Unsupported data type.");
286 if(!addArraysToAssociation(
287 block->GetCellData(), jsonVtkDataSet,
"cellData")) {
288 this->
printErr(
"Unsupported data type.");
291 if(!addArraysToAssociation(
292 block->GetFieldData(), jsonVtkDataSet,
"fieldData")) {
293 this->
printErr(
"Unsupported data type.");
297 this->LastOutput->SetBlock(b++, block);
301 "Parsing vtkDataObject from JSON string", 1, timer.
getElapsedTime());
317 if(object->IsA(
"vtkMultiBlockDataSet"))
318 objectAsMB->ShallowCopy(
object);
320 objectAsMB->SetBlock(0,
object);
322 const size_t nBlocks = objectAsMB->GetNumberOfBlocks();
323 for(
size_t b = 0; b < nBlocks; b++) {
324 auto block = vtkDataSet::SafeDownCast(objectAsMB->GetBlock(b));
326 this->
printErr(
"Input `vtkDataObject` is not a `vtkDataSet` or a "
327 "`vtkMultiBlockDataSet` containing only `vtkDataSets`.");
333 + std::string(block->GetClassName()) +
"\" }");
339 if(block->IsA(
"vtkImageData")) {
340 auto lastInputAsID = vtkImageData::SafeDownCast(block);
344 lastInputAsID->GetDimensions(dimension);
345 lastInputAsID->GetOrigin(origin);
346 lastInputAsID->GetSpacing(spacing);
351 + std::to_string(dimension[0]) +
"," + std::to_string(dimension[1])
352 +
"," + std::to_string(dimension[2])
355 + std::to_string(origin[0]) +
"," + std::to_string(origin[1]) +
","
356 + std::to_string(origin[2])
359 + std::to_string(spacing[0]) +
"," + std::to_string(spacing[1]) +
","
360 + std::to_string(spacing[2])
369 auto blockAsPS = vtkPointSet::SafeDownCast(block);
370 if(blockAsPS !=
nullptr) {
371 auto points = blockAsPS->GetPoints();
374 "\"target\": \"points\","
375 "\"name\": \"coordinates\","
377 + std::to_string(points ? points->GetDataType() : VTK_FLOAT)
380 + std::to_string(blockAsPS->GetNumberOfPoints())
384 if(blockAsPS->GetNumberOfPoints() > 0 && points !=
nullptr)
385 switch(points->GetDataType()) {
387 blockAsPS->GetNumberOfPoints() *
sizeof(VTK_TT) * 3,
397 vtkCellArray *cells =
nullptr;
399 if(block->IsA(
"vtkUnstructuredGrid")) {
400 auto blockAsUG = vtkUnstructuredGrid::SafeDownCast(block);
401 if(blockAsUG !=
nullptr) {
402 cells = blockAsUG->GetCells();
404 }
else if(block->IsA(
"vtkPolyData")) {
405 auto blockAsPD = vtkPolyData::SafeDownCast(block);
406 if(blockAsPD !=
nullptr) {
407 cells = blockAsPD->GetPolys() ? blockAsPD->GetPolys()
408 : blockAsPD->GetLines();
414 auto connectivityArray = cells->GetConnectivityArray();
417 "\"target\": \"cells\","
418 "\"name\": \"connectivityArray\","
420 + std::to_string(VTK_ID_TYPE)
423 + std::to_string(connectivityArray->GetNumberOfTuples())
427 if(connectivityArray->GetNumberOfTuples() > 0)
429 connectivityArray->GetNumberOfTuples() *
sizeof(vtkIdType),
434 auto offsetsArray = cells->GetOffsetsArray();
436 "\"target\": \"cells\","
437 "\"name\": \"offsetsArray\","
439 + std::to_string(VTK_ID_TYPE)
442 + std::to_string(offsetsArray->GetNumberOfTuples())
446 if(offsetsArray->GetNumberOfTuples() > 0)
448 offsetsArray->GetNumberOfTuples() *
sizeof(vtkIdType),
459 std::vector<std::pair<std::string, vtkFieldData *>> attributes
460 = {{
"pointData", block->GetPointData()},
461 {
"cellData", block->GetCellData()},
462 {
"fieldData", block->GetFieldData()}};
464 for(
auto &attribute : attributes) {
465 size_t nArrays = attribute.second->GetNumberOfArrays();
467 for(
size_t i = 0; i < nArrays; i++) {
468 auto array = attribute.second->GetAbstractArray(i);
470 if(array->IsA(
"vtkDataArray")) {
471 auto dataArray = vtkDataArray::SafeDownCast(array);
472 if(dataArray ==
nullptr) {
481 + std::string(dataArray->GetName())
484 + std::to_string(dataArray->GetDataType())
487 + std::to_string(dataArray->GetNumberOfTuples())
490 + std::to_string(dataArray->GetNumberOfComponents()) +
"}");
491 if(dataArray->GetNumberOfValues() > 0)
492 switch(dataArray->GetDataType()) {
494 dataArray->GetNumberOfValues() *
sizeof(VTK_TT),
497 }
else if(array->IsA(
"vtkStringArray")) {
498 auto stringArray = vtkStringArray::SafeDownCast(array);
500 values += stringArray->GetValue(0);
501 for(
int j = 1; j < stringArray->GetNumberOfValues(); j++)
502 values +=
"," + stringArray->GetValue(j);
510 + std::string(stringArray->GetName())
513 + std::to_string(stringArray->GetDataType())
516 + std::to_string(stringArray->GetNumberOfTuples())
519 + std::to_string(stringArray->GetNumberOfComponents())
522 + boost::replace_all_copy(values,
"\"",
"\\\"")
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
static void * GetVoidPointer(vtkDataArray *array, vtkIdType start=0)
static int stringListToDoubleVector(const std::string &iString, std::vector< double > &v)
static int stringListToVector(const std::string &iString, std::vector< std::string > &v)
int FillOutputPortInformation(int port, vtkInformation *info) override
virtual void SetNeedsUpdate(bool)
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int processEvent(const std::string &eventName, const std::string &eventData="") override
virtual bool GetNeedsUpdate()
int SendVtkDataObject(vtkDataObject *object)
~ttkWebSocketIO() override
int FillInputPortInformation(int port, vtkInformation *info) override
int ParseVtkDataObjectFromJSON(const std::string &json)
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
int queueMessage(const std::string &msg)
int processMessageQueue()
int startServer(int PortNumber)
T jsonGetValue(const boost::property_tree::ptree &pt, const boost::property_tree::ptree::key_type &key)
vtkStandardNewMacro(ttkWebSocketIO)
void jsonArrayToArray(const boost::property_tree::ptree &pt, const boost::property_tree::ptree::key_type &key, T *result)