1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkResliceCursorLineRepresentation.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 "vtkResliceCursorLineRepresentation.h"
16 #include "vtkActor2D.h"
17 #include "vtkBoundingBox.h"
18 #include "vtkCamera.h"
19 #include "vtkCoordinate.h"
20 #include "vtkHandleRepresentation.h"
21 #include "vtkImageActor.h"
22 #include "vtkImageData.h"
23 #include "vtkImageReslice.h"
24 #include "vtkInteractorObserver.h"
25 #include "vtkLine.h"
26 #include "vtkMath.h"
27 #include "vtkMatrix4x4.h"
28 #include "vtkNew.h"
29 #include "vtkObjectFactory.h"
30 #include "vtkPlane.h"
31 #include "vtkPlaneSource.h"
32 #include "vtkPointHandleRepresentation2D.h"
33 #include "vtkPoints.h"
34 #include "vtkPolyData.h"
35 #include "vtkPolyDataMapper2D.h"
36 #include "vtkProperty2D.h"
37 #include "vtkRenderer.h"
38 #include "vtkResliceCursor.h"
39 #include "vtkResliceCursorActor.h"
40 #include "vtkResliceCursorPicker.h"
41 #include "vtkResliceCursorPolyDataAlgorithm.h"
42 #include "vtkSmartPointer.h"
43 #include "vtkTextActor.h"
44 #include "vtkTextMapper.h"
45 #include "vtkTextProperty.h"
46 #include "vtkTransform.h"
47 #include "vtkWindow.h"
48 
49 #include <sstream>
50 
51 vtkStandardNewMacro(vtkResliceCursorLineRepresentation);
52 
53 //------------------------------------------------------------------------------
vtkResliceCursorLineRepresentation()54 vtkResliceCursorLineRepresentation::vtkResliceCursorLineRepresentation()
55 {
56   this->ResliceCursorActor = vtkResliceCursorActor::New();
57 
58   this->Picker = vtkResliceCursorPicker::New();
59   this->Picker->SetTolerance(0.025);
60 
61   this->MatrixReslice = vtkMatrix4x4::New();
62   this->MatrixView = vtkMatrix4x4::New();
63   this->MatrixReslicedView = vtkMatrix4x4::New();
64 }
65 
66 //------------------------------------------------------------------------------
~vtkResliceCursorLineRepresentation()67 vtkResliceCursorLineRepresentation::~vtkResliceCursorLineRepresentation()
68 {
69   this->ResliceCursorActor->Delete();
70   this->Picker->Delete();
71   this->MatrixReslice->Delete();
72   this->MatrixView->Delete();
73   this->MatrixReslicedView->Delete();
74 }
75 
76 //------------------------------------------------------------------------------
GetResliceCursor()77 vtkResliceCursor* vtkResliceCursorLineRepresentation::GetResliceCursor()
78 {
79   return this->ResliceCursorActor->GetCursorAlgorithm()->GetResliceCursor();
80 }
81 
82 //------------------------------------------------------------------------------
ComputeInteractionState(int X,int Y,int modify)83 int vtkResliceCursorLineRepresentation::ComputeInteractionState(int X, int Y, int modify)
84 {
85   this->InteractionState = vtkResliceCursorLineRepresentation::Outside;
86 
87   if (!this->Renderer)
88   {
89     return this->InteractionState;
90   }
91 
92   vtkResliceCursor* rc = this->GetResliceCursor();
93   if (!rc)
94   {
95     vtkErrorMacro(<< "Reslice cursor not set!");
96     return this->InteractionState;
97   }
98 
99   this->Modifier = modify;
100 
101   // Ensure that the axis is initialized..
102   const int axis1 = this->ResliceCursorActor->GetCursorAlgorithm()->GetAxis1();
103   double bounds[6];
104   this->ResliceCursorActor->GetCenterlineActor(axis1)->GetBounds(bounds);
105   if (bounds[1] < bounds[0])
106   {
107     return this->InteractionState;
108   }
109 
110   // Pick
111   this->Picker->SetResliceCursorAlgorithm(this->ResliceCursorActor->GetCursorAlgorithm());
112   int picked = this->Picker->Pick(X, Y, 0, this->Renderer);
113 
114   const bool pickedAxis1 = this->Picker->GetPickedAxis1() ? true : false;
115   const bool pickedAxis2 = this->Picker->GetPickedAxis2() ? true : false;
116   const bool pickedCenter = this->Picker->GetPickedCenter() ? true : false;
117   if (picked)
118   {
119     this->Picker->GetPickPosition(this->StartPickPosition);
120   }
121 
122   // Now assign the interaction state
123 
124   if (pickedCenter)
125   {
126     this->InteractionState = vtkResliceCursorLineRepresentation::OnCenter;
127   }
128   else if (pickedAxis1)
129   {
130     this->InteractionState = vtkResliceCursorLineRepresentation::OnAxis1;
131   }
132   else if (pickedAxis2)
133   {
134     this->InteractionState = vtkResliceCursorLineRepresentation::OnAxis2;
135   }
136 
137   return this->InteractionState;
138 }
139 
140 //------------------------------------------------------------------------------
141 // Record the current event position, and the center position.
StartWidgetInteraction(double startEventPos[2])142 void vtkResliceCursorLineRepresentation ::StartWidgetInteraction(double startEventPos[2])
143 {
144   this->StartEventPosition[0] = startEventPos[0];
145   this->StartEventPosition[1] = startEventPos[1];
146 
147   if (this->ManipulationMode == WindowLevelling)
148   {
149     this->InitialWindow = this->CurrentWindow;
150     this->InitialLevel = this->CurrentLevel;
151   }
152   else
153   {
154     if (vtkResliceCursor* rc = this->GetResliceCursor())
155     {
156       rc->GetCenter(this->StartCenterPosition);
157     }
158   }
159 
160   this->LastEventPosition[0] = startEventPos[0];
161   this->LastEventPosition[1] = startEventPos[1];
162 }
163 
164 //------------------------------------------------------------------------------
WidgetInteraction(double e[2])165 void vtkResliceCursorLineRepresentation::WidgetInteraction(double e[2])
166 {
167   vtkResliceCursor* rc = this->GetResliceCursor();
168 
169   if (this->ManipulationMode == WindowLevelling)
170   {
171     this->WindowLevel(e[0], e[1]);
172     this->LastEventPosition[0] = e[0];
173     this->LastEventPosition[1] = e[1];
174     return;
175   }
176 
177   // Depending on the state, different motions are allowed.
178 
179   if (this->InteractionState == Outside || !this->Renderer || !rc)
180   {
181     this->LastEventPosition[0] = e[0];
182     this->LastEventPosition[1] = e[1];
183     return;
184   }
185 
186   if (rc->GetThickMode() &&
187     this->ManipulationMode == vtkResliceCursorRepresentation::ResizeThickness)
188   {
189 
190     double sf = 1.0;
191 
192     // Compute the scale factor
193     const int* size = this->Renderer->GetSize();
194     double dPos = e[1] - this->LastEventPosition[1];
195     sf *= (1.0 + 2.0 * (dPos / size[1])); // scale factor of 2.0 is arbitrary
196 
197     double thickness[3];
198     rc->GetThickness(thickness);
199     rc->SetThickness(thickness[0] * sf, thickness[1] * sf, thickness[2] * sf);
200 
201     this->LastEventPosition[0] = e[0];
202     this->LastEventPosition[1] = e[1];
203 
204     return;
205   }
206 
207   // depending on the state, perform different operations
208   //
209   // 1. Translation
210 
211   if (this->InteractionState == OnCenter && !this->Modifier)
212   {
213 
214     // Intersect with the viewing vector. We will use this point and the
215     // start event point to compute an offset vector to translate the
216     // center by.
217 
218     double intersectionPos[3], newCenter[3];
219     this->Picker->Pick(e, intersectionPos, this->Renderer);
220 
221     // Offset the center by this vector.
222 
223     for (int i = 0; i < 3; i++)
224     {
225       newCenter[i] = this->StartCenterPosition[i] + intersectionPos[i] - this->StartPickPosition[i];
226     }
227 
228     rc->SetCenter(newCenter);
229   }
230 
231   // 2. Rotation of axis 1
232 
233   if (this->InteractionState == OnAxis1 && !this->Modifier)
234   {
235     this->RotateAxis(e, this->ResliceCursorActor->GetCursorAlgorithm()->GetPlaneAxis1());
236   }
237 
238   // 3. Rotation of axis 2
239 
240   if (this->InteractionState == OnAxis2 && !this->Modifier)
241   {
242     this->RotateAxis(e, this->ResliceCursorActor->GetCursorAlgorithm()->GetPlaneAxis2());
243   }
244 
245   // 4. Rotation of both axes
246 
247   if ((this->InteractionState == OnAxis2 || this->InteractionState == OnAxis1) && this->Modifier)
248   {
249     // Rotate both by the same angle
250     const double angle =
251       this->RotateAxis(e, this->ResliceCursorActor->GetCursorAlgorithm()->GetPlaneAxis1());
252     this->RotateAxis(this->ResliceCursorActor->GetCursorAlgorithm()->GetPlaneAxis2(), angle);
253   }
254 
255   this->LastEventPosition[0] = e[0];
256   this->LastEventPosition[1] = e[1];
257 }
258 
259 //------------------------------------------------------------------------------
RotateAxis(double e[2],int axis)260 double vtkResliceCursorLineRepresentation ::RotateAxis(double e[2], int axis)
261 {
262   vtkResliceCursor* rc = this->GetResliceCursor();
263 
264   double center[3];
265   rc->GetCenter(center);
266 
267   // Intersect with the viewing vector. We will use this point and the
268   // start event point to compute the rotation angle
269 
270   double currIntersectionPos[3], lastIntersectionPos[3];
271   this->DisplayToReslicePlaneIntersection(e, currIntersectionPos);
272   this->DisplayToReslicePlaneIntersection(this->LastEventPosition, lastIntersectionPos);
273 
274   if (lastIntersectionPos[0] == currIntersectionPos[0] &&
275     lastIntersectionPos[1] == currIntersectionPos[1] &&
276     lastIntersectionPos[2] == currIntersectionPos[2])
277   {
278     return 0;
279   }
280 
281   double lastVector[3], currVector[3];
282   for (int i = 0; i < 3; i++)
283   {
284     lastVector[i] = lastIntersectionPos[i] - center[i];
285     currVector[i] = currIntersectionPos[i] - center[i];
286   }
287 
288   vtkMath::Normalize(lastVector);
289   vtkMath::Normalize(currVector);
290 
291   // compute the angle betweem both vectors. This is the amount to
292   // rotate by.
293   double angle = acos(vtkMath::Dot(lastVector, currVector));
294   double crossVector[3];
295   vtkMath::Cross(lastVector, currVector, crossVector);
296 
297   double aboutAxis[3];
298   const int rcPlaneIdx = this->ResliceCursorActor->GetCursorAlgorithm()->GetReslicePlaneNormal();
299   vtkPlane* normalPlane = rc->GetPlane(rcPlaneIdx);
300   normalPlane->GetNormal(aboutAxis);
301   const double align = vtkMath::Dot(aboutAxis, crossVector);
302   const double sign = align > 0 ? 1.0 : -1.0;
303   angle *= sign;
304 
305   if (angle == 0)
306   {
307     return 0;
308   }
309 
310   this->RotateAxis(axis, angle);
311 
312   return angle;
313 }
314 
315 //------------------------------------------------------------------------------
316 // Get the plane normal to the viewing axis.
GetCursorAlgorithm()317 vtkResliceCursorPolyDataAlgorithm* vtkResliceCursorLineRepresentation::GetCursorAlgorithm()
318 {
319   return this->ResliceCursorActor->GetCursorAlgorithm();
320 }
321 
322 //------------------------------------------------------------------------------
RotateAxis(int axis,double angle)323 void vtkResliceCursorLineRepresentation ::RotateAxis(int axis, double angle)
324 {
325   vtkResliceCursor* rc = this->GetResliceCursor();
326   vtkPlane* planeToBeRotated = rc->GetPlane(axis);
327   double* viewUp = rc->GetViewUp(axis);
328 
329   const int rcPlaneIdx = this->ResliceCursorActor->GetCursorAlgorithm()->GetReslicePlaneNormal();
330 
331   vtkPlane* normalPlane = rc->GetPlane(rcPlaneIdx);
332 
333   double vectorToBeRotated[3], aboutAxis[3], rotatedVector[3];
334   planeToBeRotated->GetNormal(vectorToBeRotated);
335   normalPlane->GetNormal(aboutAxis);
336 
337   this->RotateVectorAboutVector(vectorToBeRotated, aboutAxis, angle, rotatedVector);
338   this->RotateVectorAboutVector(viewUp, aboutAxis, angle, viewUp);
339   planeToBeRotated->SetNormal(rotatedVector);
340 }
341 
342 //------------------------------------------------------------------------------
RotateVectorAboutVector(double vectorToBeRotated[3],double axis[3],double angle,double o[3])343 void vtkResliceCursorLineRepresentation ::RotateVectorAboutVector(double vectorToBeRotated[3],
344   double axis[3], // vector about which we rotate
345   double angle,   // angle in radians
346   double o[3])
347 {
348   vtkNew<vtkTransform> transform;
349   transform->RotateWXYZ(vtkMath::DegreesFromRadians(angle), axis);
350   transform->TransformVector(vectorToBeRotated, o);
351 }
352 
353 //------------------------------------------------------------------------------
DisplayToReslicePlaneIntersection(double displayPos[2],double intersectionPos[3])354 int vtkResliceCursorLineRepresentation ::DisplayToReslicePlaneIntersection(
355   double displayPos[2], double intersectionPos[3])
356 {
357   // First compute the equivalent of this display point on the focal plane
358   double fp[4], tmp1[4], camPos[4], eventFPpos[4];
359   this->Renderer->GetActiveCamera()->GetFocalPoint(fp);
360   this->Renderer->GetActiveCamera()->GetPosition(camPos);
361   fp[3] = 1.0;
362   this->Renderer->SetWorldPoint(fp);
363   this->Renderer->WorldToDisplay();
364   this->Renderer->GetDisplayPoint(tmp1);
365 
366   tmp1[0] = displayPos[0];
367   tmp1[1] = displayPos[1];
368   this->Renderer->SetDisplayPoint(tmp1);
369   this->Renderer->DisplayToWorld();
370   this->Renderer->GetWorldPoint(eventFPpos);
371 
372   const int rcPlaneIdx = this->ResliceCursorActor->GetCursorAlgorithm()->GetReslicePlaneNormal();
373   vtkPlane* normalPlane = this->GetResliceCursor()->GetPlane(rcPlaneIdx);
374 
375   double t;
376 
377   return normalPlane->IntersectWithLine(eventFPpos, camPos, t, intersectionPos);
378 }
379 
380 //------------------------------------------------------------------------------
BuildRepresentation()381 void vtkResliceCursorLineRepresentation::BuildRepresentation()
382 {
383   if (this->GetMTime() > this->BuildTime ||
384     this->GetResliceCursor()->GetMTime() > this->BuildTime ||
385     (this->Renderer && this->Renderer->GetVTKWindow() &&
386       this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime))
387   {
388 
389     this->BuildTime.Modified();
390   }
391 
392   this->Superclass::BuildRepresentation();
393 }
394 
395 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * w)396 void vtkResliceCursorLineRepresentation::ReleaseGraphicsResources(vtkWindow* w)
397 {
398   this->ResliceCursorActor->ReleaseGraphicsResources(w);
399   this->TexturePlaneActor->ReleaseGraphicsResources(w);
400   this->ImageActor->ReleaseGraphicsResources(w);
401   this->TextActor->ReleaseGraphicsResources(w);
402 }
403 
404 //------------------------------------------------------------------------------
RenderOverlay(vtkViewport * viewport)405 int vtkResliceCursorLineRepresentation::RenderOverlay(vtkViewport* viewport)
406 {
407   int count = 0;
408 
409   if (this->TexturePlaneActor->GetVisibility() && !this->UseImageActor)
410   {
411     count += this->TexturePlaneActor->RenderOverlay(viewport);
412   }
413   if (this->ImageActor->GetVisibility() && this->UseImageActor)
414   {
415     count += this->ImageActor->RenderOverlay(viewport);
416   }
417   if (this->DisplayText && this->TextActor->GetVisibility())
418   {
419     count += this->TextActor->RenderOverlay(viewport);
420   }
421 
422   return count;
423 }
424 
425 //------------------------------------------------------------------------------
SetUserMatrix(vtkMatrix4x4 * m)426 void vtkResliceCursorLineRepresentation::SetUserMatrix(vtkMatrix4x4* m)
427 {
428   this->TexturePlaneActor->SetUserMatrix(m);
429   this->ResliceCursorActor->SetUserMatrix(m);
430 }
431 
432 //------------------------------------------------------------------------------
RenderOpaqueGeometry(vtkViewport * viewport)433 int vtkResliceCursorLineRepresentation ::RenderOpaqueGeometry(vtkViewport* viewport)
434 {
435   this->BuildRepresentation();
436 
437   const int normalAxis = this->ResliceCursorActor->GetCursorAlgorithm()->GetReslicePlaneNormal();
438 
439   // When the reslice plane is changed, update the camera to look at the
440   // normal to the reslice plane always.
441 
442   double fp[3], cp[3], n[3];
443   this->Renderer->GetActiveCamera()->GetFocalPoint(fp);
444   this->Renderer->GetActiveCamera()->GetPosition(cp);
445   this->GetResliceCursor()->GetPlane(normalAxis)->GetNormal(n);
446 
447   const double d = sqrt(vtkMath::Distance2BetweenPoints(cp, fp));
448   double newCamPos[3] = { fp[0] + (d * n[0]), fp[1] + (d * n[1]), fp[2] + (d * n[2]) };
449   this->Renderer->GetActiveCamera()->SetPosition(newCamPos);
450 
451   // intersect with the plane to get updated focal point
452   double intersectionPos[3], t;
453   this->GetResliceCursor()
454     ->GetPlane(normalAxis)
455     ->IntersectWithLine(fp, newCamPos, t, intersectionPos);
456   this->Renderer->GetActiveCamera()->SetFocalPoint(intersectionPos);
457 
458   // Don't clip away any part of the data.
459   this->Renderer->ResetCameraClippingRange();
460 
461   // Now Render all the actors.
462 
463   int count = 0;
464   if (this->TexturePlaneActor->GetVisibility() && !this->UseImageActor)
465   {
466     count += this->TexturePlaneActor->RenderOpaqueGeometry(viewport);
467   }
468   if (this->ImageActor->GetVisibility() && this->UseImageActor)
469   {
470     count += this->ImageActor->RenderOpaqueGeometry(viewport);
471   }
472   count += this->ResliceCursorActor->RenderOpaqueGeometry(viewport);
473   if (this->DisplayText && this->TextActor->GetVisibility())
474   {
475     count += this->TextActor->RenderOpaqueGeometry(viewport);
476   }
477 
478   return count;
479 }
480 
481 //------------------------------------------------------------------------------
482 // Get the bounds for this Actor as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
GetBounds()483 double* vtkResliceCursorLineRepresentation::GetBounds()
484 {
485   vtkMath::UninitializeBounds(this->InitialBounds);
486 
487   if (vtkResliceCursor* r = this->GetResliceCursor())
488   {
489     r->GetImage()->GetBounds(this->InitialBounds);
490   }
491 
492   // vtkBoundingBox *bb = new vtkBoundingBox();
493   // bb->AddBounds(this->ResliceCursorActor->GetBounds());
494   // bb->AddBounds(this->TexturePlaneActor->GetBounds());
495   // bb->GetBounds(bounds);
496   // delete bb;
497 
498   return this->InitialBounds;
499 }
500 
501 //------------------------------------------------------------------------------
RenderTranslucentPolygonalGeometry(vtkViewport * viewport)502 int vtkResliceCursorLineRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport* viewport)
503 {
504   int count = 0;
505   if (this->TexturePlaneActor->GetVisibility() && !this->UseImageActor)
506   {
507     count += this->TexturePlaneActor->RenderTranslucentPolygonalGeometry(viewport);
508   }
509 
510   if (this->ImageActor->GetVisibility() && this->UseImageActor)
511   {
512     count += this->ImageActor->RenderTranslucentPolygonalGeometry(viewport);
513   }
514 
515   count += this->ResliceCursorActor->RenderTranslucentPolygonalGeometry(viewport);
516 
517   return count;
518 }
519 
520 //------------------------------------------------------------------------------
HasTranslucentPolygonalGeometry()521 vtkTypeBool vtkResliceCursorLineRepresentation::HasTranslucentPolygonalGeometry()
522 {
523   return (this->ResliceCursorActor->HasTranslucentPolygonalGeometry() ||
524            (this->ImageActor->HasTranslucentPolygonalGeometry() && this->UseImageActor) ||
525            (this->TexturePlaneActor->HasTranslucentPolygonalGeometry() && !this->UseImageActor))
526     ? 1
527     : 0;
528 }
529 
530 //------------------------------------------------------------------------------
Highlight(int)531 void vtkResliceCursorLineRepresentation::Highlight(int) {}
532 
533 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)534 void vtkResliceCursorLineRepresentation::PrintSelf(ostream& os, vtkIndent indent)
535 {
536   // Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
537   this->Superclass::PrintSelf(os, indent);
538 
539   os << indent << "ResliceCursorActor: " << this->ResliceCursorActor << "\n";
540   if (this->ResliceCursorActor)
541   {
542     this->ResliceCursorActor->PrintSelf(os, indent);
543   }
544 
545   os << indent << "Picker: " << this->Picker << "\n";
546   if (this->Picker)
547   {
548     this->Picker->PrintSelf(os, indent);
549   }
550 
551   os << indent << "MatrixReslicedView: " << this->MatrixReslicedView << "\n";
552   if (this->MatrixReslicedView)
553   {
554     this->MatrixReslicedView->PrintSelf(os, indent);
555   }
556 
557   os << indent << "MatrixView: " << this->MatrixView << "\n";
558   if (this->MatrixView)
559   {
560     this->MatrixView->PrintSelf(os, indent);
561   }
562 
563   os << indent << "MatrixReslice: " << this->MatrixReslice << "\n";
564   if (this->MatrixReslice)
565   {
566     this->MatrixReslice->PrintSelf(os, indent);
567   }
568 
569   // this->StartPickPosition;
570   // this->StartCenterPosition;
571 }
572