1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkMNITagPointWriter.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 /*=========================================================================
16
17 Copyright (c) 2006 Atamai, Inc.
18
19 Use, modification and redistribution of the software, in source or
20 binary forms, are permitted provided that the following terms and
21 conditions are met:
22
23 1) Redistribution of the source code, in verbatim or modified
24 form, must retain the above copyright notice, this license,
25 the following disclaimer, and any notices that refer to this
26 license and/or the following disclaimer.
27
28 2) Redistribution in binary form must include the above copyright
29 notice, a copy of this license and the following disclaimer
30 in the documentation or with other materials provided with the
31 distribution.
32
33 3) Modified copies of the source code must be clearly marked as such,
34 and must not be misrepresented as verbatim copies of the source code.
35
36 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
37 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
38 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
40 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
41 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
42 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
43 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
44 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
45 POSSIBILITY OF SUCH DAMAGES.
46
47 =========================================================================*/
48
49 #include "vtkMNITagPointWriter.h"
50
51 #include "vtkObjectFactory.h"
52
53 #include "vtkInformationVector.h"
54 #include "vtkInformation.h"
55 #include "vtkPointSet.h"
56 #include "vtkPointData.h"
57 #include "vtkPoints.h"
58 #include "vtkStringArray.h"
59 #include "vtkDoubleArray.h"
60 #include "vtkIntArray.h"
61 #include "vtkMath.h"
62 #include "vtkErrorCode.h"
63 #include "vtkCommand.h"
64
65 #include <cctype>
66 #include <cmath>
67
68 #if !defined(_WIN32) || defined(__CYGWIN__)
69 # include <unistd.h> /* unlink */
70 #else
71 # include <io.h> /* unlink */
72 #endif
73
74 //--------------------------------------------------------------------------
75 vtkStandardNewMacro(vtkMNITagPointWriter);
76
77 vtkCxxSetObjectMacro(vtkMNITagPointWriter, LabelText, vtkStringArray);
78 vtkCxxSetObjectMacro(vtkMNITagPointWriter, Weights, vtkDoubleArray);
79 vtkCxxSetObjectMacro(vtkMNITagPointWriter, StructureIds, vtkIntArray);
80 vtkCxxSetObjectMacro(vtkMNITagPointWriter, PatientIds, vtkIntArray);
81
82 //-------------------------------------------------------------------------
vtkMNITagPointWriter()83 vtkMNITagPointWriter::vtkMNITagPointWriter()
84 {
85 this->Points[0] = nullptr;
86 this->Points[1] = nullptr;
87
88 this->LabelText = nullptr;
89 this->Weights = nullptr;
90 this->StructureIds = nullptr;
91 this->PatientIds = nullptr;
92
93 this->Comments = nullptr;
94
95 this->SetNumberOfInputPorts(2);
96 this->SetNumberOfOutputPorts(0);
97
98 this->FileName = nullptr;
99 }
100
101 //-------------------------------------------------------------------------
~vtkMNITagPointWriter()102 vtkMNITagPointWriter::~vtkMNITagPointWriter()
103 {
104 vtkObject *objects[6];
105 objects[0] = this->Points[0];
106 objects[1] = this->Points[1];
107 objects[2] = this->LabelText;
108 objects[3] = this->Weights;
109 objects[4] = this->StructureIds;
110 objects[5] = this->PatientIds;
111
112 for (int i = 0; i < 6; i++)
113 {
114 if (objects[i])
115 {
116 objects[i]->Delete();
117 }
118 }
119
120 delete [] this->Comments;
121
122 delete[] this->FileName;
123 }
124
125 //-------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)126 void vtkMNITagPointWriter::PrintSelf(ostream& os, vtkIndent indent)
127 {
128 this->Superclass::PrintSelf(os,indent);
129
130 os << indent << "Points: " << this->Points[0] << " "
131 << this->Points[1] << "\n";
132 os << indent << "LabelText: " << this->LabelText << "\n";
133 os << indent << "Weights: " << this->Weights << "\n";
134 os << indent << "StructureIds: " << this->StructureIds << "\n";
135 os << indent << "PatientIds: " << this->PatientIds << "\n";
136
137 os << indent << "Comments: "
138 << (this->Comments ? this->Comments : "none") << "\n";
139 }
140
141 //----------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)142 int vtkMNITagPointWriter::FillInputPortInformation(
143 int, vtkInformation* info)
144 {
145 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPointSet");
146 info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
147 return 1;
148 }
149
150 //-------------------------------------------------------------------------
GetMTime()151 vtkMTimeType vtkMNITagPointWriter::GetMTime()
152 {
153 vtkMTimeType mtime = this->Superclass::GetMTime();
154
155 vtkObject *objects[6];
156 objects[0] = this->Points[0];
157 objects[1] = this->Points[1];
158 objects[2] = this->LabelText;
159 objects[3] = this->Weights;
160 objects[4] = this->StructureIds;
161 objects[5] = this->PatientIds;
162
163 for (int i = 0; i < 6; i++)
164 {
165 if (objects[i])
166 {
167 vtkMTimeType m = objects[i]->GetMTime();
168 if (m > mtime)
169 {
170 mtime = m;
171 }
172 }
173 }
174
175 return mtime;
176 }
177
178 //-------------------------------------------------------------------------
SetPoints(int port,vtkPoints * points)179 void vtkMNITagPointWriter::SetPoints(int port, vtkPoints *points)
180 {
181 if (port < 0 || port > 1)
182 {
183 return;
184 }
185 if (this->Points[port] == points)
186 {
187 return;
188 }
189 if (this->Points[port])
190 {
191 this->Points[port]->Delete();
192 }
193 this->Points[port] = points;
194 if (this->Points[port])
195 {
196 this->Points[port]->Register(this);
197 }
198 this->Modified();
199 }
200
201 //-------------------------------------------------------------------------
GetPoints(int port)202 vtkPoints *vtkMNITagPointWriter::GetPoints(int port)
203 {
204 if (port < 0 || port > 1)
205 {
206 return nullptr;
207 }
208 return this->Points[port];
209 }
210
211 //-------------------------------------------------------------------------
WriteData(vtkPointSet * inputs[2])212 void vtkMNITagPointWriter::WriteData(vtkPointSet *inputs[2])
213 {
214 static const char *arrayNames[3] = {
215 "Weights",
216 "StructureIds",
217 "PatientIds"
218 };
219
220 vtkPoints *points[2];
221
222 vtkStringArray *labels = nullptr;
223 vtkDataArray *darray[3];
224 darray[0] = nullptr;
225 darray[1] = nullptr;
226 darray[2] = nullptr;
227
228 vtkDataArray *ivarArrays[3];
229 ivarArrays[0] = this->Weights;
230 ivarArrays[1] = this->StructureIds;
231 ivarArrays[2] = this->PatientIds;
232
233 for (int ii = 1; ii >= 0; --ii)
234 {
235 points[ii] = nullptr;
236 if (inputs[ii])
237 {
238 points[ii] = inputs[ii]->GetPoints();
239
240 vtkStringArray *stringArray = vtkArrayDownCast<vtkStringArray>(
241 inputs[ii]->GetPointData()->GetAbstractArray("LabelText"));
242 if (stringArray)
243 {
244 labels = stringArray;
245 }
246
247 for (int j = 0; j < 3; j++)
248 {
249 vtkDataArray *dataArray =
250 inputs[ii]->GetPointData()->GetArray(arrayNames[j]);
251 if (dataArray)
252 {
253 darray[j] = dataArray;
254 }
255 }
256 }
257
258 if (this->Points[ii])
259 {
260 points[ii] = this->Points[ii];
261 }
262 }
263
264 if (this->LabelText)
265 {
266 labels = this->LabelText;
267 }
268
269 for (int j = 0; j < 3; j++)
270 {
271 if (ivarArrays[j])
272 {
273 darray[j] = ivarArrays[j];
274 }
275 }
276
277 if (points[0] == nullptr)
278 {
279 vtkErrorMacro("No input points have been provided");
280 return;
281 }
282
283 // numVolumes is 1 if there is only one set of points
284 int numVolumes = 1;
285 vtkIdType n = points[0]->GetNumberOfPoints();
286 if (points[1])
287 {
288 numVolumes = 2;
289 if (points[1]->GetNumberOfPoints() != n)
290 {
291 vtkErrorMacro("Input point counts do not match: " << n << " versus "
292 << points[1]->GetNumberOfPoints());
293 return;
294 }
295 }
296
297 // labels is null if there are no labels
298 if (labels && labels->GetNumberOfValues() != n)
299 {
300 vtkErrorMacro("LabelText count does not match point count: "
301 << labels->GetNumberOfValues() << " versus " << n);
302 return;
303 }
304
305 // dataArrays is null if there are no data arrays
306 vtkDataArray **dataArrays = nullptr;
307 for (int jj = 0; jj < 3; jj++)
308 {
309 if (darray[jj])
310 {
311 dataArrays = darray;
312 if (darray[jj]->GetNumberOfTuples() != n)
313 {
314 vtkErrorMacro("" << arrayNames[jj]
315 << " count does not match point count: "
316 << darray[jj]->GetNumberOfTuples() << " versus " << n);
317 return;
318 }
319 }
320 }
321
322 // If we got this far, the data seems to be okay
323 ostream *outfilep = this->OpenFile();
324 if (!outfilep)
325 {
326 return;
327 }
328
329 ostream &outfile = *outfilep;
330
331 // Write the header
332 outfile << "MNI Tag Point File\n";
333 outfile << "Volumes = " << numVolumes << ";\n";
334
335 // Write user comments
336 if (this->Comments)
337 {
338 char *cp = this->Comments;
339 while (*cp)
340 {
341 if (*cp != '%')
342 {
343 outfile << "% ";
344 }
345 while (*cp && *cp != '\n')
346 {
347 if (isprint(*cp) || *cp == '\t')
348 {
349 outfile << *cp;
350 }
351 cp++;
352 }
353 outfile << "\n";
354 if (*cp == '\n')
355 {
356 cp++;
357 }
358 }
359 }
360 else
361 {
362 for (int k = 0; k < numVolumes; k++)
363 {
364 outfile << "% Volume " << (k + 1) << " produced by VTK\n";
365 }
366 }
367
368 // Add a blank line
369 outfile << "\n";
370
371 // Write the points
372 outfile << "Points =\n";
373
374 char text[256];
375 for (int i = 0; i < n; i++)
376 {
377 for (int kk = 0; kk < 2; kk++)
378 {
379 if (points[kk])
380 {
381 double point[3];
382 points[kk]->GetPoint(i, point);
383 snprintf(text, sizeof(text), " %.15g %.15g %.15g", point[0], point[1], point[2]);
384 outfile << text;
385 }
386 }
387
388 if (dataArrays)
389 {
390 double w = 0.0;
391 int s = -1;
392 int p = -1;
393 if (dataArrays[0])
394 {
395 w = dataArrays[0]->GetComponent(i, 0);
396 }
397 if (dataArrays[1])
398 {
399 s = static_cast<int>(dataArrays[1]->GetComponent(i, 0));
400 }
401 if (dataArrays[2])
402 {
403 p = static_cast<int>(dataArrays[2]->GetComponent(i, 0));
404 }
405
406 snprintf(text, sizeof(text), " %.15g %d %d", w, s, p);
407 outfile << text;
408 }
409
410 if (labels)
411 {
412 vtkStdString l = labels->GetValue(i);
413 outfile << " \"";
414 for (std::string::iterator si = l.begin(); si != l.end(); ++si)
415 {
416 if (isprint(*si) && *si != '\"' && *si != '\\')
417 {
418 outfile.put(*si);
419 }
420 else
421 {
422 outfile.put('\\');
423 char c = '\0';
424 static char ctrltable[] = {
425 '\a', 'a', '\b', 'b', '\f', 'f', '\n', 'n', '\r', 'r',
426 '\t', 't', '\v', 'v', '\\', '\\', '\"', '\"', '\0', '\0'
427 };
428 for (int ci = 0; ctrltable[ci] != '\0'; ci += 2)
429 {
430 if (*si == ctrltable[ci])
431 {
432 c = ctrltable[ci + 1];
433 break;
434 }
435 }
436 if (c != '\0')
437 {
438 outfile.put(c);
439 }
440 else
441 {
442 snprintf(text, sizeof(text), "x%2.2x", (static_cast<int>(*si) & 0x00ff));
443 outfile << text;
444 }
445 }
446 }
447
448 outfile << "\"";
449 }
450
451 if (i < n-1)
452 {
453 outfile << "\n";
454 }
455 }
456
457 outfile << ";\n";
458 outfile.flush();
459
460 // Close the file
461 this->CloseFile(outfilep);
462
463 // Delete the file if an error occurred
464 if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
465 {
466 vtkErrorMacro("Ran out of disk space; deleting file: "
467 << this->FileName);
468 unlink(this->FileName);
469 }
470 }
471
472 //-------------------------------------------------------------------------
Write()473 int vtkMNITagPointWriter::Write()
474 {
475 // Allow writer to work when no inputs are provided
476 this->Modified();
477 this->Update();
478 return 1;
479 }
480
481 //-------------------------------------------------------------------------
RequestData(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector *)482 int vtkMNITagPointWriter::RequestData(
483 vtkInformation *, vtkInformationVector **inputVector,
484 vtkInformationVector *)
485 {
486 this->SetErrorCode(vtkErrorCode::NoError);
487
488 vtkInformation *inInfo[2];
489 inInfo[0] = inputVector[0]->GetInformationObject(0);
490 inInfo[1] = inputVector[1]->GetInformationObject(0);
491
492 vtkPointSet *input[2];
493 input[0] = nullptr;
494 input[1] = nullptr;
495
496 vtkMTimeType lastUpdateTime = 0;
497 for (int idx = 0; idx < 2; ++idx)
498 {
499 if (inInfo[idx])
500 {
501 input[idx] = vtkPointSet::SafeDownCast(
502 inInfo[idx]->Get(vtkDataObject::DATA_OBJECT()));
503 if (input[idx])
504 {
505 vtkMTimeType updateTime = input[idx]->GetUpdateTime();
506 if (updateTime > lastUpdateTime)
507 {
508 lastUpdateTime = updateTime;
509 }
510 }
511 }
512 }
513
514 if (lastUpdateTime < this->WriteTime && this->GetMTime() < this->WriteTime)
515 {
516 // we are up to date
517 return 1;
518 }
519
520 this->InvokeEvent(vtkCommand::StartEvent, nullptr);
521 this->WriteData(input);
522 this->InvokeEvent(vtkCommand::EndEvent, nullptr);
523
524 this->WriteTime.Modified();
525
526 return 1;
527 }
528
529 //-------------------------------------------------------------------------
OpenFile()530 ostream *vtkMNITagPointWriter::OpenFile()
531 {
532 ostream *fptr;
533
534 if (!this->FileName )
535 {
536 vtkErrorMacro(<< "No FileName specified! Can't write!");
537 this->SetErrorCode(vtkErrorCode::NoFileNameError);
538 return nullptr;
539 }
540
541 vtkDebugMacro(<<"Opening file for writing...");
542
543 fptr = new ofstream(this->FileName, ios::out);
544
545 if (fptr->fail())
546 {
547 vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
548 this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
549 delete fptr;
550 return nullptr;
551 }
552
553 return fptr;
554 }
555
556 //-------------------------------------------------------------------------
CloseFile(ostream * fp)557 void vtkMNITagPointWriter::CloseFile(ostream *fp)
558 {
559 vtkDebugMacro(<<"Closing file\n");
560
561 delete fp;
562 }
563