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