1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkResliceCursor.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 "vtkResliceCursor.h"
16 #include "vtkMath.h"
17 #include "vtkImageData.h"
18 #include "vtkPolyData.h"
19 #include "vtkPoints.h"
20 #include "vtkPlane.h"
21 #include "vtkPlaneCollection.h"
22 #include "vtkCellArray.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkSmartPointer.h"
25
26 #include <cmath>
27
28
29 //----------------------------------------------------------------------------
30 vtkStandardNewMacro(vtkResliceCursor);
31 vtkCxxSetObjectMacro(vtkResliceCursor, Image, vtkImageData);
32
33 //----------------------------------------------------------------------------
vtkResliceCursor()34 vtkResliceCursor::vtkResliceCursor()
35 {
36 this->XAxis[0] = 1.0;
37 this->XAxis[1] = 0.0;
38 this->XAxis[2] = 0.0;
39
40 this->YAxis[0] = 0.0;
41 this->YAxis[1] = 1.0;
42 this->YAxis[2] = 0.0;
43
44 this->ZAxis[0] = 0.0;
45 this->ZAxis[1] = 0.0;
46 this->ZAxis[2] = 1.0;
47
48 this->Center[0] = 0.0;
49 this->Center[1] = 0.0;
50 this->Center[2] = 0.0;
51
52 this->Thickness[0] = 0.0;
53 this->Thickness[1] = 0.0;
54 this->Thickness[2] = 0.0;
55
56 this->HoleWidth = 5.0;
57 this->HoleWidthInPixels = 16.0;
58 this->Hole = 1;
59
60 this->ThickMode = 1;
61
62 this->Image = nullptr;
63
64 this->PolyData = vtkPolyData::New();
65 vtkSmartPointer< vtkPoints > points
66 = vtkSmartPointer< vtkPoints >::New();
67 vtkSmartPointer< vtkCellArray > lines
68 = vtkSmartPointer< vtkCellArray >::New();
69 this->PolyData->SetPoints(points);
70 this->PolyData->SetLines(lines);
71
72 this->ReslicePlanes = vtkPlaneCollection::New();
73
74 // Reslice planes along the X, Y and Z axes. And the centerline and slab
75 // polydata.
76
77 for (int i = 0; i < 3; i++)
78 {
79 vtkSmartPointer< vtkPlane > plane = vtkSmartPointer< vtkPlane >::New();
80 this->ReslicePlanes->AddItem(plane);
81
82 // Centerline polydata.
83
84 this->CenterlineAxis[i] = vtkPolyData::New();
85
86 vtkSmartPointer< vtkPoints > pointsc
87 = vtkSmartPointer< vtkPoints >::New();
88 vtkSmartPointer< vtkCellArray > linesc
89 = vtkSmartPointer< vtkCellArray >::New();
90
91 this->CenterlineAxis[i]->SetPoints(pointsc);
92 this->CenterlineAxis[i]->SetLines(linesc);
93
94 }
95
96 this->ReslicePlanes->GetItem(0)->SetNormal(1,0,0);
97 this->ReslicePlanes->GetItem(1)->SetNormal(0,-1,0);
98 this->ReslicePlanes->GetItem(2)->SetNormal(0,0,1);
99
100 this->BuildCursorTopology();
101 }
102
103 //----------------------------------------------------------------------------
~vtkResliceCursor()104 vtkResliceCursor::~vtkResliceCursor()
105 {
106 this->SetImage(nullptr);
107 this->PolyData->Delete();
108 this->ReslicePlanes->Delete();
109
110 for (int i = 0; i < 3; i++)
111 {
112 this->CenterlineAxis[i]->Delete();
113 }
114 }
115
116 //----------------------------------------------------------------------------
BuildCursorTopology()117 void vtkResliceCursor::BuildCursorTopology()
118 {
119 if (this->Hole)
120 {
121 this->BuildCursorTopologyWithHole();
122 }
123 else
124 {
125 this->BuildCursorTopologyWithoutHole();
126 }
127 }
128
129 //----------------------------------------------------------------------------
BuildCursorTopologyWithoutHole()130 void vtkResliceCursor::BuildCursorTopologyWithoutHole()
131 {
132 vtkIdType ptIds[2];
133
134 for (int i = 0; i < 3; i++)
135 {
136 this->CenterlineAxis[i]->GetPoints()->SetNumberOfPoints(2);
137 this->CenterlineAxis[i]->GetLines()->Reset();
138
139 ptIds[0] = 0;
140 ptIds[1] = 1;
141 this->CenterlineAxis[i]->GetLines()->InsertNextCell(2, ptIds);
142 }
143 }
144
145 //----------------------------------------------------------------------------
BuildCursorTopologyWithHole()146 void vtkResliceCursor::BuildCursorTopologyWithHole()
147 {
148 vtkIdType ptIds[2];
149
150 for (int i = 0; i < 3; i++)
151 {
152 this->CenterlineAxis[i]->GetPoints()->SetNumberOfPoints(4);
153 this->CenterlineAxis[i]->GetLines()->Reset();
154
155 ptIds[0] = 0;
156 ptIds[1] = 1;
157 this->CenterlineAxis[i]->GetLines()->InsertNextCell(2, ptIds);
158 ptIds[0] = 2;
159 ptIds[1] = 3;
160 this->CenterlineAxis[i]->GetLines()->InsertNextCell(2, ptIds);
161 }
162 }
163
164 //----------------------------------------------------------------------------
165 // Reset the cursor to the default position, ie with the axes, normal
166 // to each other and axis aligned and with the cursor pointed at the
167 // center of the image.
168 //
Reset()169 void vtkResliceCursor::Reset()
170 {
171 this->XAxis[0] = 1.0;
172 this->XAxis[1] = 0.0;
173 this->XAxis[2] = 0.0;
174
175 this->YAxis[0] = 0.0;
176 this->YAxis[1] = 1.0;
177 this->YAxis[2] = 0.0;
178
179 this->ZAxis[0] = 0.0;
180 this->ZAxis[1] = 0.0;
181 this->ZAxis[2] = 1.0;
182
183 if (this->GetImage())
184 {
185 this->GetImage()->GetCenter(this->Center);
186 }
187 else
188 {
189 this->Center[0] = 0.0;
190 this->Center[1] = 0.0;
191 this->Center[2] = 0.0;
192 }
193
194 for (int i = 0; i < 3; i++)
195 {
196 this->GetPlane(i)->SetOrigin(this->Center);
197 }
198
199 this->ReslicePlanes->GetItem(0)->SetNormal(1,0,0);
200 this->ReslicePlanes->GetItem(1)->SetNormal(0,-1,0);
201 this->ReslicePlanes->GetItem(2)->SetNormal(0,0,1);
202
203 this->BuildCursorTopology();
204 this->BuildCursorGeometry();
205
206 this->Modified();
207 }
208
209 //----------------------------------------------------------------------------
GetPlane(int i)210 vtkPlane * vtkResliceCursor::GetPlane( int i )
211 {
212 return this->ReslicePlanes->GetItem(i);
213 }
214
215 //----------------------------------------------------------------------------
GetPolyData()216 vtkPolyData * vtkResliceCursor::GetPolyData()
217 {
218 this->Update();
219 return this->PolyData;
220 }
221
222 //----------------------------------------------------------------------------
Update()223 void vtkResliceCursor::Update()
224 {
225 if (!this->Image)
226 {
227 vtkErrorMacro( << "Image not set !" );
228 return;
229 }
230
231 if (this->GetMTime() > this->PolyDataBuildTime)
232 {
233 this->BuildCursorTopology();
234 this->BuildCursorGeometry();
235 }
236 }
237
238 //----------------------------------------------------------------------------
ComputeAxes()239 void vtkResliceCursor::ComputeAxes()
240 {
241 double normals[3][3];
242 for (int i = 0; i < 3; i++)
243 {
244 this->GetPlane(i)->GetNormal(normals[i]);
245 }
246
247 // The axes are the intersections of the plane normals.
248
249 vtkMath::Cross(normals[0], normals[1], this->ZAxis);
250 vtkMath::Cross(normals[1], normals[2], this->XAxis);
251 vtkMath::Cross(normals[2], normals[0], this->YAxis);
252 }
253
254 //----------------------------------------------------------------------------
BuildCursorGeometryWithHole()255 void vtkResliceCursor::BuildCursorGeometryWithHole()
256 {
257 this->ComputeAxes();
258
259 double bounds[6];
260 this->Image->GetBounds(bounds);
261
262 // Length of the principal diagonal.
263 const double pdLength = 20 * 0.5 * sqrt(
264 (bounds[1] - bounds[0])*(bounds[1] - bounds[0]) +
265 (bounds[3] - bounds[2])*(bounds[3] - bounds[2]) +
266 (bounds[5] - bounds[4])*(bounds[5] - bounds[4]));
267
268
269 // Precompute prior to use within the loop.
270 const double holeHalfWidth = this->HoleWidth / 2.0;
271
272
273 double pts[12][3];
274 for (int i = 0; i < 3; i++)
275 {
276 pts[0][i] = this->Center[i] - pdLength * this->XAxis[i];
277 pts[1][i] = this->Center[i] + pdLength * this->XAxis[i];
278 pts[2][i] = this->Center[i] - pdLength * this->YAxis[i];
279 pts[3][i] = this->Center[i] + pdLength * this->YAxis[i];
280 pts[4][i] = this->Center[i] - pdLength * this->ZAxis[i];
281 pts[5][i] = this->Center[i] + pdLength * this->ZAxis[i];
282
283 // Break in the polydata to satisfy the hole
284
285 pts[6][i] = this->Center[i] - holeHalfWidth * this->XAxis[i];
286 pts[7][i] = this->Center[i] + holeHalfWidth * this->XAxis[i];
287 pts[8][i] = this->Center[i] - holeHalfWidth * this->YAxis[i];
288 pts[9][i] = this->Center[i] + holeHalfWidth * this->YAxis[i];
289 pts[10][i] = this->Center[i] - holeHalfWidth * this->ZAxis[i];
290 pts[11][i] = this->Center[i] + holeHalfWidth * this->ZAxis[i];
291 }
292
293 for (int j = 0; j < 3; j++)
294 {
295 vtkPoints *centerlinePoints = this->CenterlineAxis[j]->GetPoints();
296 centerlinePoints->SetPoint(0, pts[2*j]);
297 centerlinePoints->SetPoint(1, pts[6+2*j]);
298 centerlinePoints->SetPoint(2, pts[6+2*j+1]);
299 centerlinePoints->SetPoint(3, pts[2*j+1]);
300
301 this->CenterlineAxis[j]->Modified();
302 }
303
304 this->PolyDataBuildTime.Modified();
305 }
306
307 //----------------------------------------------------------------------------
BuildCursorGeometryWithoutHole()308 void vtkResliceCursor::BuildCursorGeometryWithoutHole()
309 {
310 this->ComputeAxes();
311
312 double bounds[6];
313 this->Image->GetBounds(bounds);
314
315 // Length of the principal diagonal.
316 const double pdLength = 20 * 0.5 * sqrt(
317 (bounds[1] - bounds[0])*(bounds[1] - bounds[0]) +
318 (bounds[3] - bounds[2])*(bounds[3] - bounds[2]) +
319 (bounds[5] - bounds[4])*(bounds[5] - bounds[4]));
320
321
322 // Precompute prior to use within the loop.
323 double pts[6][3];
324 for (int i = 0; i < 3; i++)
325 {
326 pts[0][i] = this->Center[i] - pdLength * this->XAxis[i];
327 pts[1][i] = this->Center[i] + pdLength * this->XAxis[i];
328 pts[2][i] = this->Center[i] - pdLength * this->YAxis[i];
329 pts[3][i] = this->Center[i] + pdLength * this->YAxis[i];
330 pts[4][i] = this->Center[i] - pdLength * this->ZAxis[i];
331 pts[5][i] = this->Center[i] + pdLength * this->ZAxis[i];
332 }
333
334 for (int j = 0; j < 3; j++)
335 {
336 vtkPoints *centerlinePoints = this->CenterlineAxis[j]->GetPoints();
337 centerlinePoints->SetPoint(0, pts[2*j]);
338 centerlinePoints->SetPoint(1, pts[2*j+1]);
339
340 this->CenterlineAxis[j]->Modified();
341 }
342
343 this->PolyDataBuildTime.Modified();
344 }
345
346 //----------------------------------------------------------------------------
BuildCursorGeometry()347 void vtkResliceCursor::BuildCursorGeometry()
348 {
349 if (this->Hole)
350 {
351 this->BuildCursorGeometryWithHole();
352 }
353 else
354 {
355 this->BuildCursorGeometryWithoutHole();
356 }
357 }
358
359 //----------------------------------------------------------------------------
BuildPolyData()360 void vtkResliceCursor::BuildPolyData()
361 {
362 this->ComputeAxes();
363
364 double bounds[6];
365 this->Image->GetBounds(bounds);
366
367 // Length of the principal diagonal.
368 const double pdLength = 20 * 0.5 * sqrt(
369 (bounds[1] - bounds[0])*(bounds[1] - bounds[0]) +
370 (bounds[3] - bounds[2])*(bounds[3] - bounds[2]) +
371 (bounds[5] - bounds[4])*(bounds[5] - bounds[4]));
372
373
374 vtkSmartPointer< vtkPoints > points
375 = vtkSmartPointer< vtkPoints >::New();
376 vtkSmartPointer< vtkCellArray > lines
377 = vtkSmartPointer< vtkCellArray >::New();
378
379 // Precompute the half thickness prior to use within the loop.
380 const double ht[3] = { this->Thickness[0] / 2.0,
381 this->Thickness[1] / 2.0,
382 this->Thickness[2] / 2.0 };
383
384 points->Allocate(24);
385 lines->Allocate(lines->Allocate(lines->EstimateSize(18,4)));
386
387 double pts[30][3];
388 for (int i = 0; i < 3; i++)
389 {
390 pts[0][i] = this->Center[i] - pdLength * this->XAxis[i];
391 pts[1][i] = this->Center[i] + pdLength * this->XAxis[i];
392 pts[2][i] = pts[0][i] - ht[1] * this->YAxis[i] - ht[2] * this->ZAxis[i];
393 pts[3][i] = pts[1][i] - ht[1] * this->YAxis[i] - ht[2] * this->ZAxis[i];
394 pts[4][i] = pts[0][i] + ht[1] * this->YAxis[i] - ht[2] * this->ZAxis[i];
395 pts[5][i] = pts[1][i] + ht[1] * this->YAxis[i] - ht[2] * this->ZAxis[i];
396 pts[6][i] = pts[0][i] + ht[1] * this->YAxis[i] + ht[2] * this->ZAxis[i];
397 pts[7][i] = pts[1][i] + ht[1] * this->YAxis[i] + ht[2] * this->ZAxis[i];
398 pts[8][i] = pts[0][i] - ht[1] * this->YAxis[i] + ht[2] * this->ZAxis[i];
399 pts[9][i] = pts[1][i] - ht[1] * this->YAxis[i] + ht[2] * this->ZAxis[i];
400
401 pts[10][i] = this->Center[i] - pdLength * this->YAxis[i];
402 pts[11][i] = this->Center[i] + pdLength * this->YAxis[i];
403 pts[12][i] = pts[10][i] - ht[0] * this->XAxis[i] - ht[2] * this->ZAxis[i];
404 pts[13][i] = pts[11][i] - ht[0] * this->XAxis[i] - ht[2] * this->ZAxis[i];
405 pts[14][i] = pts[10][i] + ht[0] * this->XAxis[i] - ht[2] * this->ZAxis[i];
406 pts[15][i] = pts[11][i] + ht[0] * this->XAxis[i] - ht[2] * this->ZAxis[i];
407 pts[16][i] = pts[10][i] + ht[0] * this->XAxis[i] + ht[2] * this->ZAxis[i];
408 pts[17][i] = pts[11][i] + ht[0] * this->XAxis[i] + ht[2] * this->ZAxis[i];
409 pts[18][i] = pts[10][i] - ht[0] * this->XAxis[i] + ht[2] * this->ZAxis[i];
410 pts[19][i] = pts[11][i] - ht[0] * this->XAxis[i] + ht[2] * this->ZAxis[i];
411
412 pts[20][i] = this->Center[i] - pdLength * this->ZAxis[i];
413 pts[21][i] = this->Center[i] + pdLength * this->ZAxis[i];
414 pts[22][i] = pts[20][i] - ht[1] * this->YAxis[i] - ht[0] * this->XAxis[i];
415 pts[23][i] = pts[21][i] - ht[1] * this->YAxis[i] - ht[0] * this->XAxis[i];
416 pts[24][i] = pts[20][i] + ht[1] * this->YAxis[i] - ht[0] * this->XAxis[i];
417 pts[25][i] = pts[21][i] + ht[1] * this->YAxis[i] - ht[0] * this->XAxis[i];
418 pts[26][i] = pts[20][i] + ht[1] * this->YAxis[i] + ht[0] * this->XAxis[i];
419 pts[27][i] = pts[21][i] + ht[1] * this->YAxis[i] + ht[0] * this->XAxis[i];
420 pts[28][i] = pts[20][i] - ht[1] * this->YAxis[i] + ht[0] * this->XAxis[i];
421 pts[29][i] = pts[21][i] - ht[1] * this->YAxis[i] + ht[0] * this->XAxis[i];
422 }
423
424 vtkIdType ptIds[2];
425
426 vtkIdType facePtIds[6][4] =
427 { { 0, 2, 4, 6 }, { 1, 7, 5, 3 }, { 1,3,2,0 }, { 0,6,7,1 }, { 2,3,5,4 }, {6,4,5,7} };
428
429 for (int j = 0; j < 3; j++)
430 {
431
432 vtkPoints *centerlinePoints = this->CenterlineAxis[j]->GetPoints();
433
434 for (int i = 0; i < 4; i++)
435 {
436 ptIds[0] = 10 * j + 2 + 2*i;
437 ptIds[1] = ptIds[0] + 1;
438
439 points->InsertNextPoint(pts[ptIds[0]]);
440 points->InsertNextPoint(pts[ptIds[1]]);
441 }
442
443 centerlinePoints->SetPoint(0, pts[10*j]);
444 centerlinePoints->SetPoint(1, pts[10*j+1]);
445
446 vtkSmartPointer< vtkCellArray > slabPolys =
447 vtkSmartPointer< vtkCellArray >::New();
448 slabPolys->Allocate(slabPolys->EstimateSize(6,4));
449
450 for (int i = 0; i < 6; i++)
451 {
452 vtkIdType currFacePtIds[4] = {facePtIds[i][0] + 8*j,
453 facePtIds[i][1] + 8*j,
454 facePtIds[i][2] + 8*j,
455 facePtIds[i][3] + 8*j };
456 lines->InsertNextCell(4,currFacePtIds);
457 slabPolys->InsertNextCell(4,facePtIds[i]);
458 }
459
460 this->CenterlineAxis[j]->Modified();
461 }
462
463 this->PolyData->SetPolys(lines);
464
465 this->PolyData->SetPoints(points);
466 this->PolyData->Modified();
467
468 this->PolyDataBuildTime.Modified();
469 }
470
471 //----------------------------------------------------------------------------
SetCenter(double _arg1,double _arg2,double _arg3)472 void vtkResliceCursor::SetCenter( double _arg1, double _arg2, double _arg3 )
473 {
474 if ( (this->Center[0] != _arg1)
475 ||(this->Center[1] != _arg2)
476 ||(this->Center[2] != _arg3))
477 {
478
479 // Ensure that the center of the cursor lies within the image bounds.
480
481 if (this->Image)
482 {
483 double bounds[6];
484 this->Image->GetBounds(bounds);
485 if (_arg1 < bounds[0] || _arg1 > bounds[1] ||
486 _arg2 < bounds[2] || _arg2 > bounds[3] ||
487 _arg3 < bounds[4] || _arg3 > bounds[5])
488 {
489 return;
490 }
491 }
492
493 this->Center[0] = _arg1;
494 this->Center[1] = _arg2;
495 this->Center[2] = _arg3;
496 this->Modified();
497
498 this->GetPlane(0)->SetOrigin(this->Center);
499 this->GetPlane(1)->SetOrigin(this->Center);
500 this->GetPlane(2)->SetOrigin(this->Center);
501 }
502 }
503
504 //----------------------------------------------------------------------------
SetCenter(double _arg[3])505 void vtkResliceCursor::SetCenter(double _arg[3])
506 {
507 this->SetCenter(_arg[0], _arg[1], _arg[2]);
508 }
509
510 //----------------------------------------------------------------------------
GetCenterlineAxisPolyData(int axis)511 vtkPolyData * vtkResliceCursor::GetCenterlineAxisPolyData( int axis )
512 {
513 this->Update();
514 return this->CenterlineAxis[axis];
515 }
516
517 //----------------------------------------------------------------------------
GetAxis(int i)518 double * vtkResliceCursor::GetAxis( int i )
519 {
520 if (i == 0)
521 {
522 return this->XAxis;
523 }
524 else if (i == 1)
525 {
526 return this->YAxis;
527 }
528 else
529 {
530 return this->ZAxis;
531 }
532 }
533
534 //----------------------------------------------------------------------------
GetMTime()535 vtkMTimeType vtkResliceCursor::GetMTime()
536 {
537 vtkMTimeType mTime=this->Superclass::GetMTime();
538 for (int i = 0; i < 3; i++)
539 {
540 vtkMTimeType time = this->GetPlane(i)->GetMTime();
541 if (time > mTime)
542 {
543 mTime = time;
544 }
545 }
546
547 return mTime;
548 }
549
550 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)551 void vtkResliceCursor::PrintSelf(ostream& os, vtkIndent indent)
552 {
553 this->Superclass::PrintSelf(os,indent);
554
555 os << indent << "Hole: ";
556 if (this->Hole)
557 {
558 os << indent << "On" << "\n";
559 }
560 else
561 {
562 os << indent << "Off" << "\n";
563 }
564 os << indent << "ThickMode: ";
565 if (this->ThickMode)
566 {
567 os << indent << "On" << "\n";
568 }
569 else
570 {
571 os << indent << "Off" << "\n";
572 }
573 os << indent << "HoleWidth: " << this->HoleWidth << endl;
574 os << indent << "HoleWidthInPixels: " << this->HoleWidthInPixels << endl;
575 os << indent << "Thickness: (" << this->Thickness[0] << ","
576 << this->Thickness[1] << "," << this->Thickness[2] << ")" << endl;
577 os << indent << "Center: (" << this->Center[0] << "," << this->Center[1]
578 << this->Center[2] << endl;
579 os << indent << "XAxis: (" << this->XAxis[0] << "," << this->XAxis[1]
580 << this->XAxis[2] << endl;
581 os << indent << "YAxis: (" << this->YAxis[0] << "," << this->YAxis[1]
582 << this->YAxis[2] << endl;
583 os << indent << "ZAxis: (" << this->ZAxis[0] << "," << this->ZAxis[1]
584 << this->ZAxis[2] << endl;
585 os << indent << "Center: (" << this->Center[0] << "," << this->Center[1]
586 << this->Center[2] << endl;
587 os << indent << "Image: " << this->Image << "\n";
588 if (this->Image)
589 {
590 this->Image->PrintSelf(os, indent);
591 }
592 os << indent << "PolyData: " << this->PolyData << "\n";
593 if (this->PolyData)
594 {
595 this->PolyData->PrintSelf(os, indent);
596 }
597 os << indent << "ReslicePlanes: " << this->ReslicePlanes << "\n";
598 if (this->ReslicePlanes)
599 {
600 this->ReslicePlanes->PrintSelf(os, indent);
601 }
602
603 // this->PolyDataBuildTime;
604 // this->CenterlineAxis[3];
605
606 }
607