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