1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkBoxRepresentation.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 #include "vtkBoxRepresentation.h"
17 
18 #include "vtkActor.h"
19 #include "vtkAssemblyPath.h"
20 #include "vtkBox.h"
21 #include "vtkCallbackCommand.h"
22 #include "vtkCamera.h"
23 #include "vtkCellArray.h"
24 #include "vtkCellPicker.h"
25 #include "vtkDoubleArray.h"
26 #include "vtkEventData.h"
27 #include "vtkInteractorObserver.h"
28 #include "vtkMath.h"
29 #include "vtkObjectFactory.h"
30 #include "vtkPickingManager.h"
31 #include "vtkPlane.h"
32 #include "vtkPlanes.h"
33 #include "vtkPolyData.h"
34 #include "vtkPolyDataMapper.h"
35 #include "vtkProperty.h"
36 #include "vtkQuaternion.h"
37 #include "vtkRenderWindow.h"
38 #include "vtkRenderWindowInteractor.h"
39 #include "vtkRenderer.h"
40 #include "vtkSphereSource.h"
41 #include "vtkTransform.h"
42 #include "vtkVectorOperators.h"
43 #include "vtkWindow.h"
44 
45 #include <cassert>
46 
47 vtkStandardNewMacro(vtkBoxRepresentation);
48 
49 //------------------------------------------------------------------------------
vtkBoxRepresentation()50 vtkBoxRepresentation::vtkBoxRepresentation()
51 {
52   // The initial state
53   this->InteractionState = vtkBoxRepresentation::Outside;
54   this->TwoPlaneMode = false;
55   this->SnappedOrientation[0] = false;
56   this->SnappedOrientation[1] = false;
57   this->SnappedOrientation[2] = false;
58   this->SnapToAxes = false;
59 
60   // Handle size is in pixels for this widget
61   this->HandleSize = 5.0;
62 
63   // Control orientation of normals
64   this->InsideOut = 0;
65   this->OutlineFaceWires = 0;
66   this->OutlineCursorWires = 1;
67 
68   for (int i = 0; i < 6; ++i)
69   {
70     this->Planes[i] = vtkPlane::New();
71   }
72 
73   // Set up the initial properties
74   this->CreateDefaultProperties();
75 
76   // Construct the poly data representing the hex
77   this->HexPolyData = vtkPolyData::New();
78   this->HexMapper = vtkPolyDataMapper::New();
79   this->HexMapper->SetInputData(HexPolyData);
80   this->HexActor = vtkActor::New();
81   this->HexActor->SetMapper(this->HexMapper);
82   this->HexActor->SetProperty(this->OutlineProperty);
83 
84   // Construct initial points
85   this->Points = vtkPoints::New(VTK_DOUBLE);
86   this->Points->SetNumberOfPoints(15); // 8 corners; 6 faces; 1 center
87   this->HexPolyData->SetPoints(this->Points);
88 
89   // Construct connectivity for the faces. These are used to perform
90   // the picking.
91   int i;
92   vtkIdType pts[4];
93   vtkCellArray* cells = vtkCellArray::New();
94   cells->AllocateEstimate(6, 4);
95   pts[0] = 3;
96   pts[1] = 0;
97   pts[2] = 4;
98   pts[3] = 7;
99   cells->InsertNextCell(4, pts);
100   pts[0] = 1;
101   pts[1] = 2;
102   pts[2] = 6;
103   pts[3] = 5;
104   cells->InsertNextCell(4, pts);
105   pts[0] = 0;
106   pts[1] = 1;
107   pts[2] = 5;
108   pts[3] = 4;
109   cells->InsertNextCell(4, pts);
110   pts[0] = 2;
111   pts[1] = 3;
112   pts[2] = 7;
113   pts[3] = 6;
114   cells->InsertNextCell(4, pts);
115   pts[0] = 0;
116   pts[1] = 3;
117   pts[2] = 2;
118   pts[3] = 1;
119   cells->InsertNextCell(4, pts);
120   pts[0] = 4;
121   pts[1] = 5;
122   pts[2] = 6;
123   pts[3] = 7;
124   cells->InsertNextCell(4, pts);
125   this->HexPolyData->SetPolys(cells);
126   cells->Delete();
127   this->HexPolyData->BuildCells();
128 
129   // The face of the hexahedra
130   cells = vtkCellArray::New();
131   cells->AllocateEstimate(1, 4);
132   cells->InsertNextCell(4, pts); // temporary, replaced later
133   this->HexFacePolyData = vtkPolyData::New();
134   this->HexFacePolyData->SetPoints(this->Points);
135   this->HexFacePolyData->SetPolys(cells);
136   this->HexFaceMapper = vtkPolyDataMapper::New();
137   this->HexFaceMapper->SetInputData(HexFacePolyData);
138   this->HexFace = vtkActor::New();
139   this->HexFace->SetMapper(this->HexFaceMapper);
140   this->HexFace->SetProperty(this->FaceProperty);
141   cells->Delete();
142 
143   // Create the outline for the hex
144   this->OutlinePolyData = vtkPolyData::New();
145   this->OutlinePolyData->SetPoints(this->Points);
146   this->OutlineMapper = vtkPolyDataMapper::New();
147   this->OutlineMapper->SetInputData(this->OutlinePolyData);
148   this->HexOutline = vtkActor::New();
149   this->HexOutline->SetMapper(this->OutlineMapper);
150   this->HexOutline->SetProperty(this->OutlineProperty);
151   cells = vtkCellArray::New();
152   cells->AllocateEstimate(15, 2);
153   this->OutlinePolyData->SetLines(cells);
154   cells->Delete();
155 
156   // Create the outline
157   this->GenerateOutline();
158 
159   // Create the handles
160   this->Handle = new vtkActor*[7];
161   this->HandleMapper = new vtkPolyDataMapper*[7];
162   this->HandleGeometry = new vtkSphereSource*[7];
163   for (i = 0; i < 7; i++)
164   {
165     this->HandleGeometry[i] = vtkSphereSource::New();
166     this->HandleGeometry[i]->SetOutputPointsPrecision(vtkAlgorithm::DOUBLE_PRECISION);
167     this->HandleGeometry[i]->SetThetaResolution(16);
168     this->HandleGeometry[i]->SetPhiResolution(8);
169     this->HandleMapper[i] = vtkPolyDataMapper::New();
170     this->HandleMapper[i]->SetInputConnection(this->HandleGeometry[i]->GetOutputPort());
171     this->Handle[i] = vtkActor::New();
172     this->Handle[i]->SetMapper(this->HandleMapper[i]);
173     this->Handle[i]->SetProperty(this->HandleProperty);
174   }
175 
176   // Define the point coordinates
177   double bounds[6];
178   bounds[0] = -0.5;
179   bounds[1] = 0.5;
180   bounds[2] = -0.5;
181   bounds[3] = 0.5;
182   bounds[4] = -0.5;
183   bounds[5] = 0.5;
184   // Points 8-14 are down by PositionHandles();
185   this->BoundingBox = vtkBox::New();
186   this->PlaceWidget(bounds);
187 
188   // Manage the picking stuff
189   this->HandlePicker = vtkCellPicker::New();
190   this->HandlePicker->SetTolerance(0.001);
191   for (i = 0; i < 7; i++)
192   {
193     this->HandlePicker->AddPickList(this->Handle[i]);
194   }
195   this->HandlePicker->PickFromListOn();
196 
197   this->HexPicker = vtkCellPicker::New();
198   this->HexPicker->SetTolerance(0.001);
199   this->HexPicker->AddPickList(HexActor);
200   this->HexPicker->PickFromListOn();
201 
202   this->CurrentHandle = nullptr;
203 
204   // Internal data members for performance
205   this->Transform = vtkTransform::New();
206   this->PlanePoints = vtkPoints::New(VTK_DOUBLE);
207   this->PlanePoints->SetNumberOfPoints(6);
208   this->PlaneNormals = vtkDoubleArray::New();
209   this->PlaneNormals->SetNumberOfComponents(3);
210   this->PlaneNormals->SetNumberOfTuples(6);
211   this->Matrix = vtkMatrix4x4::New();
212 
213   this->TranslationAxis = Axis::NONE;
214 }
215 
216 //------------------------------------------------------------------------------
~vtkBoxRepresentation()217 vtkBoxRepresentation::~vtkBoxRepresentation()
218 {
219   this->HexActor->Delete();
220   this->HexMapper->Delete();
221   this->HexPolyData->Delete();
222   this->Points->Delete();
223 
224   this->HexFace->Delete();
225   this->HexFaceMapper->Delete();
226   this->HexFacePolyData->Delete();
227 
228   this->HexOutline->Delete();
229   this->OutlineMapper->Delete();
230   this->OutlinePolyData->Delete();
231 
232   for (int i = 0; i < 7; i++)
233   {
234     this->HandleGeometry[i]->Delete();
235     this->HandleMapper[i]->Delete();
236     this->Handle[i]->Delete();
237   }
238   delete[] this->Handle;
239   delete[] this->HandleMapper;
240   delete[] this->HandleGeometry;
241 
242   this->HandlePicker->Delete();
243   this->HexPicker->Delete();
244 
245   this->Transform->Delete();
246   this->BoundingBox->Delete();
247   this->PlanePoints->Delete();
248   this->PlaneNormals->Delete();
249   this->Matrix->Delete();
250 
251   this->HandleProperty->Delete();
252   this->SelectedHandleProperty->Delete();
253   this->FaceProperty->Delete();
254   this->SelectedFaceProperty->Delete();
255   this->OutlineProperty->Delete();
256   this->SelectedOutlineProperty->Delete();
257 
258   for (int i = 0; i < 6; ++i)
259   {
260     this->Planes[i]->Delete();
261   }
262 }
263 
264 //------------------------------------------------------------------------------
GetPolyData(vtkPolyData * pd)265 void vtkBoxRepresentation::GetPolyData(vtkPolyData* pd)
266 {
267   pd->SetPoints(this->HexPolyData->GetPoints());
268   pd->SetPolys(this->HexPolyData->GetPolys());
269 }
270 
271 //------------------------------------------------------------------------------
StartWidgetInteraction(double e[2])272 void vtkBoxRepresentation::StartWidgetInteraction(double e[2])
273 {
274   // Store the start position
275   this->StartEventPosition[0] = e[0];
276   this->StartEventPosition[1] = e[1];
277   this->StartEventPosition[2] = 0.0;
278 
279   // Store the start position
280   this->LastEventPosition[0] = e[0];
281   this->LastEventPosition[1] = e[1];
282   this->LastEventPosition[2] = 0.0;
283 
284   this->ComputeInteractionState(static_cast<int>(e[0]), static_cast<int>(e[1]), 0);
285 }
286 
StartComplexInteraction(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void * calldata)287 void vtkBoxRepresentation::StartComplexInteraction(
288   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void* calldata)
289 {
290   vtkEventData* edata = static_cast<vtkEventData*>(calldata);
291   vtkEventDataDevice3D* edd = edata->GetAsEventDataDevice3D();
292   if (edd)
293   {
294     edd->GetWorldPosition(this->StartEventPosition);
295     this->LastEventPosition[0] = this->StartEventPosition[0];
296     this->LastEventPosition[1] = this->StartEventPosition[1];
297     this->LastEventPosition[2] = this->StartEventPosition[2];
298     edd->GetWorldOrientation(this->StartEventOrientation);
299     std::copy(
300       this->StartEventOrientation, this->StartEventOrientation + 4, this->LastEventOrientation);
301     for (int i = 0; i < 3; ++i)
302     {
303       if (this->SnappedOrientation[i])
304       {
305         std::copy(this->StartEventOrientation, this->StartEventOrientation + 4,
306           this->SnappedEventOrientations[i]);
307       }
308     }
309   }
310 }
311 
SetTwoPlaneMode(bool val)312 void vtkBoxRepresentation::SetTwoPlaneMode(bool val)
313 {
314   if (this->TwoPlaneMode == val)
315   {
316     return;
317   }
318 
319   this->TwoPlaneMode = val;
320   if (this->TwoPlaneMode)
321   {
322     for (int i = 2; i < 6; i++)
323     {
324       this->HandlePicker->DeletePickList(this->Handle[i]);
325       this->Handle[i]->VisibilityOff();
326     }
327   }
328   else
329   {
330     for (int i = 2; i < 6; i++)
331     {
332       this->HandlePicker->AddPickList(this->Handle[i]);
333       this->Handle[i]->SetVisibility(this->Handle[0]->GetVisibility());
334     }
335   }
336   this->GenerateOutline();
337   this->Modified();
338 }
339 //------------------------------------------------------------------------------
WidgetInteraction(double e[2])340 void vtkBoxRepresentation::WidgetInteraction(double e[2])
341 {
342   // Convert events to appropriate coordinate systems
343   vtkCamera* camera = this->Renderer->GetActiveCamera();
344   if (!camera)
345   {
346     return;
347   }
348   double focalPoint[4], pickPoint[4], prevPickPoint[4];
349   double z, vpn[3];
350   camera->GetViewPlaneNormal(vpn);
351 
352   // Compute the two points defining the motion vector
353   double pos[3];
354   if (this->LastPicker == this->HexPicker)
355   {
356     this->HexPicker->GetPickPosition(pos);
357   }
358   else
359   {
360     this->HandlePicker->GetPickPosition(pos);
361   }
362   vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, pos[0], pos[1], pos[2], focalPoint);
363   z = focalPoint[2];
364   vtkInteractorObserver::ComputeDisplayToWorld(
365     this->Renderer, this->LastEventPosition[0], this->LastEventPosition[1], z, prevPickPoint);
366   vtkInteractorObserver::ComputeDisplayToWorld(this->Renderer, e[0], e[1], z, pickPoint);
367 
368   // Process the motion
369   if (this->InteractionState == vtkBoxRepresentation::MoveF0)
370   {
371     this->MoveMinusXFace(prevPickPoint, pickPoint);
372   }
373 
374   else if (this->InteractionState == vtkBoxRepresentation::MoveF1)
375   {
376     this->MovePlusXFace(prevPickPoint, pickPoint);
377   }
378 
379   else if (this->InteractionState == vtkBoxRepresentation::MoveF2)
380   {
381     this->MoveMinusYFace(prevPickPoint, pickPoint);
382   }
383 
384   else if (this->InteractionState == vtkBoxRepresentation::MoveF3)
385   {
386     this->MovePlusYFace(prevPickPoint, pickPoint);
387   }
388 
389   else if (this->InteractionState == vtkBoxRepresentation::MoveF4)
390   {
391     this->MoveMinusZFace(prevPickPoint, pickPoint);
392   }
393 
394   else if (this->InteractionState == vtkBoxRepresentation::MoveF5)
395   {
396     this->MovePlusZFace(prevPickPoint, pickPoint);
397   }
398 
399   else if (this->InteractionState == vtkBoxRepresentation::Translating)
400   {
401     this->Translate(prevPickPoint, pickPoint);
402   }
403 
404   else if (this->InteractionState == vtkBoxRepresentation::Scaling)
405   {
406     this->Scale(prevPickPoint, pickPoint, static_cast<int>(e[0]), static_cast<int>(e[1]));
407   }
408 
409   else if (this->InteractionState == vtkBoxRepresentation::Rotating)
410   {
411     this->Rotate(static_cast<int>(e[0]), static_cast<int>(e[1]), prevPickPoint, pickPoint, vpn);
412   }
413 
414   // Store the start position
415   this->LastEventPosition[0] = e[0];
416   this->LastEventPosition[1] = e[1];
417   this->LastEventPosition[2] = 0.0;
418 }
419 
ComplexInteraction(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void * calldata)420 void vtkBoxRepresentation::ComplexInteraction(
421   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void* calldata)
422 {
423   vtkEventData* edata = static_cast<vtkEventData*>(calldata);
424   vtkEventDataDevice3D* edd = edata->GetAsEventDataDevice3D();
425   if (edd)
426   {
427     // all others
428     double eventPos[3];
429     edd->GetWorldPosition(eventPos);
430     double eventDir[4];
431     edd->GetWorldOrientation(eventDir);
432 
433     double* prevPickPoint = this->LastEventPosition;
434     double* pickPoint = eventPos;
435 
436     if (this->InteractionState == vtkBoxRepresentation::MoveF0)
437     {
438       this->MoveMinusXFace(prevPickPoint, pickPoint);
439     }
440 
441     else if (this->InteractionState == vtkBoxRepresentation::MoveF1)
442     {
443       this->MovePlusXFace(prevPickPoint, pickPoint);
444     }
445 
446     else if (this->InteractionState == vtkBoxRepresentation::MoveF2)
447     {
448       this->MoveMinusYFace(prevPickPoint, pickPoint);
449     }
450 
451     else if (this->InteractionState == vtkBoxRepresentation::MoveF3)
452     {
453       this->MovePlusYFace(prevPickPoint, pickPoint);
454     }
455 
456     else if (this->InteractionState == vtkBoxRepresentation::MoveF4)
457     {
458       this->MoveMinusZFace(prevPickPoint, pickPoint);
459     }
460 
461     else if (this->InteractionState == vtkBoxRepresentation::MoveF5)
462     {
463       this->MovePlusZFace(prevPickPoint, pickPoint);
464     }
465 
466     else if (this->InteractionState == vtkBoxRepresentation::Translating)
467     {
468       this->UpdatePose(this->LastEventPosition, this->LastEventOrientation, eventPos, eventDir);
469     }
470 
471     // Book keeping
472     std::copy(eventPos, eventPos + 3, this->LastEventPosition);
473     std::copy(eventDir, eventDir + 4, this->LastEventOrientation);
474     this->Modified();
475   }
476 }
477 
StepForward()478 void vtkBoxRepresentation::StepForward()
479 {
480   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
481   this->Translate(pts, pts + 3);
482 }
483 
StepBackward()484 void vtkBoxRepresentation::StepBackward()
485 {
486   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
487   this->Translate(pts + 3, pts);
488 }
489 
EndComplexInteraction(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void *)490 void vtkBoxRepresentation::EndComplexInteraction(
491   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void*)
492 {
493 }
494 
495 //------------------------------------------------------------------------------
MoveFace(const double * p1,const double * p2,const double * dir,double * x1,double * x2,double * x3,double * x4,double * x5)496 void vtkBoxRepresentation::MoveFace(const double* p1, const double* p2, const double* dir,
497   double* x1, double* x2, double* x3, double* x4, double* x5)
498 {
499   int i;
500   double v[3], v2[3];
501 
502   for (i = 0; i < 3; i++)
503   {
504     v[i] = p2[i] - p1[i];
505     v2[i] = dir[i];
506   }
507 
508   vtkMath::Normalize(v2);
509   double f = vtkMath::Dot(v, v2);
510 
511   for (i = 0; i < 3; i++)
512   {
513     v[i] = f * v2[i];
514 
515     x1[i] += v[i];
516     x2[i] += v[i];
517     x3[i] += v[i];
518     x4[i] += v[i];
519     x5[i] += v[i];
520   }
521   this->PositionHandles();
522 }
523 
524 //------------------------------------------------------------------------------
GetDirection(const double Nx[3],const double Ny[3],const double Nz[3],double dir[3])525 void vtkBoxRepresentation::GetDirection(
526   const double Nx[3], const double Ny[3], const double Nz[3], double dir[3])
527 {
528   double dotNy, dotNz;
529   double y[3];
530 
531   if (vtkMath::Dot(Nx, Nx) != 0)
532   {
533     dir[0] = Nx[0];
534     dir[1] = Nx[1];
535     dir[2] = Nx[2];
536   }
537   else
538   {
539     dotNy = vtkMath::Dot(Ny, Ny);
540     dotNz = vtkMath::Dot(Nz, Nz);
541     if (dotNy != 0 && dotNz != 0)
542     {
543       vtkMath::Cross(Ny, Nz, dir);
544     }
545     else if (dotNy != 0)
546     {
547       // dir must have been initialized to the
548       // corresponding coordinate direction before calling
549       // this method
550       vtkMath::Cross(Ny, dir, y);
551       vtkMath::Cross(y, Ny, dir);
552     }
553     else if (dotNz != 0)
554     {
555       // dir must have been initialized to the
556       // corresponding coordinate direction before calling
557       // this method
558       vtkMath::Cross(Nz, dir, y);
559       vtkMath::Cross(y, Nz, dir);
560     }
561   }
562 }
563 
564 //------------------------------------------------------------------------------
MovePlusXFace(const double * p1,const double * p2)565 void vtkBoxRepresentation::MovePlusXFace(const double* p1, const double* p2)
566 {
567   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
568 
569   double* h1 = pts + 3 * 9;
570 
571   double* x1 = pts + 3 * 1;
572   double* x2 = pts + 3 * 2;
573   double* x3 = pts + 3 * 5;
574   double* x4 = pts + 3 * 6;
575 
576   double dir[3] = { 1, 0, 0 };
577   this->ComputeNormals();
578   this->GetDirection(this->N[1], this->N[3], this->N[5], dir);
579   this->MoveFace(p1, p2, dir, x1, x2, x3, x4, h1);
580 }
581 
582 //------------------------------------------------------------------------------
MoveMinusXFace(const double * p1,const double * p2)583 void vtkBoxRepresentation::MoveMinusXFace(const double* p1, const double* p2)
584 {
585   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
586 
587   double* h1 = pts + 3 * 8;
588 
589   double* x1 = pts + 3 * 0;
590   double* x2 = pts + 3 * 3;
591   double* x3 = pts + 3 * 4;
592   double* x4 = pts + 3 * 7;
593 
594   double dir[3] = { -1, 0, 0 };
595   this->ComputeNormals();
596   this->GetDirection(this->N[0], this->N[4], this->N[2], dir);
597 
598   this->MoveFace(p1, p2, dir, x1, x2, x3, x4, h1);
599 }
600 
601 //------------------------------------------------------------------------------
MovePlusYFace(const double * p1,const double * p2)602 void vtkBoxRepresentation::MovePlusYFace(const double* p1, const double* p2)
603 {
604   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
605 
606   double* h1 = pts + 3 * 11;
607 
608   double* x1 = pts + 3 * 2;
609   double* x2 = pts + 3 * 3;
610   double* x3 = pts + 3 * 6;
611   double* x4 = pts + 3 * 7;
612 
613   double dir[3] = { 0, 1, 0 };
614   this->ComputeNormals();
615   this->GetDirection(this->N[3], this->N[5], this->N[1], dir);
616 
617   this->MoveFace(p1, p2, dir, x1, x2, x3, x4, h1);
618 }
619 
620 //------------------------------------------------------------------------------
MoveMinusYFace(const double * p1,const double * p2)621 void vtkBoxRepresentation::MoveMinusYFace(const double* p1, const double* p2)
622 {
623   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
624 
625   double* h1 = pts + 3 * 10;
626 
627   double* x1 = pts + 3 * 0;
628   double* x2 = pts + 3 * 1;
629   double* x3 = pts + 3 * 4;
630   double* x4 = pts + 3 * 5;
631 
632   double dir[3] = { 0, -1, 0 };
633   this->ComputeNormals();
634   this->GetDirection(this->N[2], this->N[0], this->N[4], dir);
635 
636   this->MoveFace(p1, p2, dir, x1, x2, x3, x4, h1);
637 }
638 
639 //------------------------------------------------------------------------------
MovePlusZFace(const double * p1,const double * p2)640 void vtkBoxRepresentation::MovePlusZFace(const double* p1, const double* p2)
641 {
642   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
643 
644   double* h1 = pts + 3 * 13;
645 
646   double* x1 = pts + 3 * 4;
647   double* x2 = pts + 3 * 5;
648   double* x3 = pts + 3 * 6;
649   double* x4 = pts + 3 * 7;
650 
651   double dir[3] = { 0, 0, 1 };
652   this->ComputeNormals();
653   this->GetDirection(this->N[5], this->N[1], this->N[3], dir);
654 
655   this->MoveFace(p1, p2, dir, x1, x2, x3, x4, h1);
656 }
657 
658 //------------------------------------------------------------------------------
MoveMinusZFace(const double * p1,const double * p2)659 void vtkBoxRepresentation::MoveMinusZFace(const double* p1, const double* p2)
660 {
661   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
662 
663   double* h1 = pts + 3 * 12;
664 
665   double* x1 = pts + 3 * 0;
666   double* x2 = pts + 3 * 1;
667   double* x3 = pts + 3 * 2;
668   double* x4 = pts + 3 * 3;
669 
670   double dir[3] = { 0, 0, -1 };
671   this->ComputeNormals();
672   this->GetDirection(this->N[4], this->N[2], this->N[0], dir);
673 
674   this->MoveFace(p1, p2, dir, x1, x2, x3, x4, h1);
675 }
676 
677 //------------------------------------------------------------------------------
678 // Loop through all points and translate them
Translate(const double * p1,const double * p2)679 void vtkBoxRepresentation::Translate(const double* p1, const double* p2)
680 {
681   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
682   double v[3] = { 0, 0, 0 };
683 
684   if (!this->IsTranslationConstrained())
685   {
686     v[0] = p2[0] - p1[0];
687     v[1] = p2[1] - p1[1];
688     v[2] = p2[2] - p1[2];
689   }
690   else
691   {
692     assert(this->TranslationAxis > -1 && this->TranslationAxis < 3 &&
693       "this->TranslationAxis out of bounds");
694     v[this->TranslationAxis] = p2[this->TranslationAxis] - p1[this->TranslationAxis];
695   }
696 
697   // Move the corners
698   for (int i = 0; i < 8; i++)
699   {
700     *pts++ += v[0];
701     *pts++ += v[1];
702     *pts++ += v[2];
703   }
704   this->PositionHandles();
705 }
706 
707 //------------------------------------------------------------------------------
Scale(const double * vtkNotUsed (p1),const double * vtkNotUsed (p2),int vtkNotUsed (X),int Y)708 void vtkBoxRepresentation::Scale(
709   const double* vtkNotUsed(p1), const double* vtkNotUsed(p2), int vtkNotUsed(X), int Y)
710 {
711   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
712   double* center = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(3 * 14);
713   double sf;
714 
715   if (Y > this->LastEventPosition[1])
716   {
717     sf = 1.03;
718   }
719   else
720   {
721     sf = 0.97;
722   }
723 
724   // Move the corners
725   for (int i = 0; i < 8; i++, pts += 3)
726   {
727     pts[0] = sf * (pts[0] - center[0]) + center[0];
728     pts[1] = sf * (pts[1] - center[1]) + center[1];
729     pts[2] = sf * (pts[2] - center[2]) + center[2];
730   }
731   this->PositionHandles();
732 }
733 
734 //------------------------------------------------------------------------------
ComputeNormals()735 void vtkBoxRepresentation::ComputeNormals()
736 {
737   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
738   double* p0 = pts;
739   double* px = pts + 3 * 1;
740   double* py = pts + 3 * 3;
741   double* pz = pts + 3 * 4;
742   int i;
743 
744   for (i = 0; i < 3; i++)
745   {
746     this->N[0][i] = p0[i] - px[i];
747     this->N[2][i] = p0[i] - py[i];
748     this->N[4][i] = p0[i] - pz[i];
749   }
750   vtkMath::Normalize(this->N[0]);
751   vtkMath::Normalize(this->N[2]);
752   vtkMath::Normalize(this->N[4]);
753   for (i = 0; i < 3; i++)
754   {
755     this->N[1][i] = -this->N[0][i];
756     this->N[3][i] = -this->N[2][i];
757     this->N[5][i] = -this->N[4][i];
758   }
759 }
760 
761 //------------------------------------------------------------------------------
GetPlanes(vtkPlanes * planes)762 void vtkBoxRepresentation::GetPlanes(vtkPlanes* planes)
763 {
764   if (!planes)
765   {
766     return;
767   }
768 
769   this->ComputeNormals();
770 
771   // Set the normals and coordinate values
772   double factor = (this->InsideOut ? -1.0 : 1.0);
773   for (int i = 0; i < 6; i++)
774   {
775     this->PlanePoints->SetPoint(i, this->Points->GetPoint(8 + i));
776     this->PlaneNormals->SetTuple3(
777       i, factor * this->N[i][0], factor * this->N[i][1], factor * this->N[i][2]);
778   }
779 
780   planes->SetPoints(this->PlanePoints);
781   planes->SetNormals(this->PlaneNormals);
782   planes->Modified();
783 }
784 
785 //------------------------------------------------------------------------------
Rotate(int X,int Y,const double * p1,const double * p2,const double * vpn)786 void vtkBoxRepresentation::Rotate(
787   int X, int Y, const double* p1, const double* p2, const double* vpn)
788 {
789   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
790   double* center = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(3 * 14);
791   double v[3];    // vector of motion
792   double axis[3]; // axis of rotation
793   double theta;   // rotation angle
794   int i;
795 
796   v[0] = p2[0] - p1[0];
797   v[1] = p2[1] - p1[1];
798   v[2] = p2[2] - p1[2];
799 
800   // Create axis of rotation and angle of rotation
801   vtkMath::Cross(vpn, v, axis);
802   if (vtkMath::Normalize(axis) == 0.0)
803   {
804     return;
805   }
806   const int* size = this->Renderer->GetSize();
807   double l2 = (X - this->LastEventPosition[0]) * (X - this->LastEventPosition[0]) +
808     (Y - this->LastEventPosition[1]) * (Y - this->LastEventPosition[1]);
809   theta = 360.0 * sqrt(l2 / (size[0] * size[0] + size[1] * size[1]));
810 
811   // Manipulate the transform to reflect the rotation
812   this->Transform->Identity();
813   this->Transform->Translate(center[0], center[1], center[2]);
814   this->Transform->RotateWXYZ(theta, axis);
815   this->Transform->Translate(-center[0], -center[1], -center[2]);
816 
817   // Set the corners
818   vtkPoints* newPts = vtkPoints::New(VTK_DOUBLE);
819   this->Transform->TransformPoints(this->Points, newPts);
820 
821   for (i = 0; i < 8; i++, pts += 3)
822   {
823     this->Points->SetPoint(i, newPts->GetPoint(i));
824   }
825 
826   newPts->Delete();
827   this->PositionHandles();
828 }
829 
830 namespace
831 {
snapToAxis(vtkVector3d & in,vtkVector3d & out,double snapAngle)832 bool snapToAxis(vtkVector3d& in, vtkVector3d& out, double snapAngle)
833 {
834   int largest = 0;
835   if (fabs(in[1]) > fabs(in[0]))
836   {
837     largest = 1;
838   }
839   if (fabs(in[2]) > fabs(in[largest]))
840   {
841     largest = 2;
842   }
843   vtkVector3d axis(0, 0, 0);
844   axis[largest] = 1.0;
845   // 3 degrees of sticky
846   if (fabs(in.Dot(axis)) > cos(vtkMath::Pi() * snapAngle / 180.0))
847   {
848     if (in.Dot(axis) < 0)
849     {
850       axis[largest] = -1;
851     }
852     out = axis;
853     return true;
854   }
855   return false;
856 }
857 }
858 
UpdatePose(const double * pos1,const double * orient1,const double * pos2,const double * orient2)859 void vtkBoxRepresentation::UpdatePose(
860   const double* pos1, const double* orient1, const double* pos2, const double* orient2)
861 {
862 
863   bool newSnap[3];
864   vtkVector3d basis[3];
865   double basisSize[3];
866 
867   vtkQuaternion<double> q2;
868   q2.SetRotationAngleAndAxis(
869     vtkMath::RadiansFromDegrees(orient2[0]), orient2[1], orient2[2], orient2[3]);
870 
871   for (int i = 0; i < 3; ++i)
872   {
873     newSnap[i] = false;
874     // compute the net rotation
875     vtkQuaternion<double> q1;
876     if (this->SnappedOrientation[i])
877     {
878       q1.SetRotationAngleAndAxis(vtkMath::RadiansFromDegrees(this->SnappedEventOrientations[i][0]),
879         this->SnappedEventOrientations[i][1], this->SnappedEventOrientations[i][2],
880         this->SnappedEventOrientations[i][3]);
881     }
882     else
883     {
884       q1.SetRotationAngleAndAxis(
885         vtkMath::RadiansFromDegrees(orient1[0]), orient1[1], orient1[2], orient1[3]);
886     }
887     q1.Conjugate();
888     vtkQuaternion<double> q3 = q2 * q1;
889     double axis[4];
890     axis[0] = vtkMath::DegreesFromRadians(q3.GetRotationAngleAndAxis(axis + 1));
891 
892     // Manipulate the transform to reflect the rotation
893     this->Transform->Identity();
894     this->Transform->RotateWXYZ(axis[0], axis[1], axis[2], axis[3]);
895 
896     // Set the corners
897     vtkPoints* newPts = vtkPoints::New(VTK_DOUBLE);
898     this->Transform->TransformPoints(this->Points, newPts);
899 
900     vtkVector3d p0(newPts->GetPoint(0));
901     vtkVector3d p1(newPts->GetPoint((i > 0 ? i + 2 : 1)));
902     basis[i] = p1 - p0;
903     basisSize[i] = 0.5 * basis[i].Normalize();
904     if (this->SnapToAxes)
905     {
906       // 14 degrees to snap in, 16 to snap out
907       // avoids noise on the boundary
908       newSnap[i] = snapToAxis(basis[i], basis[i], (this->SnappedOrientation[i] ? 16 : 14));
909     }
910     newPts->Delete();
911   }
912 
913   // orthogonalize the resulting basis
914   for (int i = 0; i < 3; ++i)
915   {
916     if (newSnap[i] || this->SnappedOrientation[i])
917     {
918       // orthogonalize the other axes
919       vtkVector3d& b0 = basis[i];
920       vtkVector3d& b1 = basis[(i + 1) % 3];
921       vtkVector3d& b2 = basis[(i + 2) % 3];
922 
923       double val = b1.Dot(b0);
924       b1 = b1 - b0 * val;
925       b1.Normalize();
926       b2 = b0.Cross(b1);
927       b2.Normalize();
928 
929       if (!this->SnappedOrientation[i])
930       {
931         std::copy(orient2, orient2 + 4, this->SnappedEventOrientations[i]);
932       }
933     }
934     this->SnappedOrientation[i] = newSnap[i];
935   }
936 
937   // get the translation
938   vtkVector3d trans;
939   for (int i = 0; i < 3; i++)
940   {
941     trans[i] = pos2[i] - pos1[i];
942   }
943 
944   vtkQuaternion<double> q1;
945   q1.SetRotationAngleAndAxis(
946     vtkMath::RadiansFromDegrees(orient1[0]), orient1[1], orient1[2], orient1[3]);
947   q1.Conjugate();
948   vtkQuaternion<double> q3 = q2 * q1;
949   double axis[4];
950   axis[0] = vtkMath::DegreesFromRadians(q3.GetRotationAngleAndAxis(axis + 1));
951 
952   // compute the new center based on the rotation
953   // point of rotation and translation
954   vtkVector3d center(static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(3 * 14));
955 
956   this->Transform->Identity();
957   this->Transform->Translate(pos1[0], pos1[1], pos1[2]);
958   this->Transform->RotateWXYZ(axis[0], axis[1], axis[2], axis[3]);
959   this->Transform->Translate(-(pos1[0]), -(pos1[1]), -(pos1[2]));
960   this->Transform->Translate(center[0], center[1], center[2]);
961 
962   this->Transform->GetPosition(center.GetData());
963   center = center + trans;
964 
965   // rebuild points based on basis vectors
966   this->Points->SetPoint(0,
967     (center - basis[0] * basisSize[0] - basis[1] * basisSize[1] - basis[2] * basisSize[2])
968       .GetData());
969   this->Points->SetPoint(1,
970     (center + basis[0] * basisSize[0] - basis[1] * basisSize[1] - basis[2] * basisSize[2])
971       .GetData());
972   this->Points->SetPoint(2,
973     (center + basis[0] * basisSize[0] + basis[1] * basisSize[1] - basis[2] * basisSize[2])
974       .GetData());
975   this->Points->SetPoint(3,
976     (center - basis[0] * basisSize[0] + basis[1] * basisSize[1] - basis[2] * basisSize[2])
977       .GetData());
978   this->Points->SetPoint(4,
979     (center - basis[0] * basisSize[0] - basis[1] * basisSize[1] + basis[2] * basisSize[2])
980       .GetData());
981   this->Points->SetPoint(5,
982     (center + basis[0] * basisSize[0] - basis[1] * basisSize[1] + basis[2] * basisSize[2])
983       .GetData());
984   this->Points->SetPoint(6,
985     (center + basis[0] * basisSize[0] + basis[1] * basisSize[1] + basis[2] * basisSize[2])
986       .GetData());
987   this->Points->SetPoint(7,
988     (center - basis[0] * basisSize[0] + basis[1] * basisSize[1] + basis[2] * basisSize[2])
989       .GetData());
990 
991   this->PositionHandles();
992 }
993 
994 //------------------------------------------------------------------------------
CreateDefaultProperties()995 void vtkBoxRepresentation::CreateDefaultProperties()
996 {
997   // Handle properties
998   this->HandleProperty = vtkProperty::New();
999   this->HandleProperty->SetColor(1, 1, 1);
1000 
1001   this->SelectedHandleProperty = vtkProperty::New();
1002   this->SelectedHandleProperty->SetColor(1, 0, 0);
1003 
1004   // Face properties
1005   this->FaceProperty = vtkProperty::New();
1006   this->FaceProperty->SetColor(1, 1, 1);
1007   this->FaceProperty->SetOpacity(0.0);
1008 
1009   this->SelectedFaceProperty = vtkProperty::New();
1010   this->SelectedFaceProperty->SetColor(1, 1, 0);
1011   this->SelectedFaceProperty->SetOpacity(0.25);
1012 
1013   // Outline properties
1014   this->OutlineProperty = vtkProperty::New();
1015   this->OutlineProperty->SetRepresentationToWireframe();
1016   this->OutlineProperty->SetAmbient(1.0);
1017   this->OutlineProperty->SetAmbientColor(1.0, 1.0, 1.0);
1018   this->OutlineProperty->SetLineWidth(2.0);
1019 
1020   this->SelectedOutlineProperty = vtkProperty::New();
1021   this->SelectedOutlineProperty->SetRepresentationToWireframe();
1022   this->SelectedOutlineProperty->SetAmbient(1.0);
1023   this->SelectedOutlineProperty->SetAmbientColor(0.0, 1.0, 0.0);
1024   this->SelectedOutlineProperty->SetLineWidth(2.0);
1025 }
1026 
1027 //------------------------------------------------------------------------------
PlaceWidget(double bds[6])1028 void vtkBoxRepresentation::PlaceWidget(double bds[6])
1029 {
1030   int i;
1031   double bounds[6], center[3];
1032 
1033   this->AdjustBounds(bds, bounds, center);
1034 
1035   this->Points->SetPoint(0, bounds[0], bounds[2], bounds[4]);
1036   this->Points->SetPoint(1, bounds[1], bounds[2], bounds[4]);
1037   this->Points->SetPoint(2, bounds[1], bounds[3], bounds[4]);
1038   this->Points->SetPoint(3, bounds[0], bounds[3], bounds[4]);
1039   this->Points->SetPoint(4, bounds[0], bounds[2], bounds[5]);
1040   this->Points->SetPoint(5, bounds[1], bounds[2], bounds[5]);
1041   this->Points->SetPoint(6, bounds[1], bounds[3], bounds[5]);
1042   this->Points->SetPoint(7, bounds[0], bounds[3], bounds[5]);
1043 
1044   for (i = 0; i < 6; i++)
1045   {
1046     this->InitialBounds[i] = bounds[i];
1047   }
1048   this->InitialLength = sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) +
1049     (bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) +
1050     (bounds[5] - bounds[4]) * (bounds[5] - bounds[4]));
1051 
1052   this->PositionHandles();
1053   this->ComputeNormals();
1054   this->ValidPick = 1; // since we have set up widget
1055   this->SizeHandles();
1056 }
1057 
1058 //------------------------------------------------------------------------------
GetTransform(vtkTransform * t)1059 void vtkBoxRepresentation::GetTransform(vtkTransform* t)
1060 {
1061   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
1062   double* p0 = pts;
1063   double* p1 = pts + 3 * 1;
1064   double* p3 = pts + 3 * 3;
1065   double* p4 = pts + 3 * 4;
1066   double* p14 = pts + 3 * 14;
1067   double center[3], translate[3], scale[3], scaleVec[3][3];
1068   double InitialCenter[3];
1069   int i;
1070 
1071   // The transformation is relative to the initial bounds.
1072   // Initial bounds are set when PlaceWidget() is invoked.
1073   t->Identity();
1074 
1075   // Translation
1076   for (i = 0; i < 3; i++)
1077   {
1078     InitialCenter[i] = (this->InitialBounds[2 * i + 1] + this->InitialBounds[2 * i]) / 2.0;
1079     center[i] = p14[i] - InitialCenter[i];
1080   }
1081   translate[0] = center[0] + InitialCenter[0];
1082   translate[1] = center[1] + InitialCenter[1];
1083   translate[2] = center[2] + InitialCenter[2];
1084   t->Translate(translate[0], translate[1], translate[2]);
1085 
1086   // Orientation
1087   this->Matrix->Identity();
1088   this->PositionHandles();
1089   this->ComputeNormals();
1090   for (i = 0; i < 3; i++)
1091   {
1092     this->Matrix->SetElement(i, 0, this->N[1][i]);
1093     this->Matrix->SetElement(i, 1, this->N[3][i]);
1094     this->Matrix->SetElement(i, 2, this->N[5][i]);
1095   }
1096   t->Concatenate(this->Matrix);
1097 
1098   // Scale
1099   for (i = 0; i < 3; i++)
1100   {
1101     scaleVec[0][i] = (p1[i] - p0[i]);
1102     scaleVec[1][i] = (p3[i] - p0[i]);
1103     scaleVec[2][i] = (p4[i] - p0[i]);
1104   }
1105 
1106   scale[0] = vtkMath::Norm(scaleVec[0]);
1107   if (this->InitialBounds[1] != this->InitialBounds[0])
1108   {
1109     scale[0] = scale[0] / (this->InitialBounds[1] - this->InitialBounds[0]);
1110   }
1111   scale[1] = vtkMath::Norm(scaleVec[1]);
1112   if (this->InitialBounds[3] != this->InitialBounds[2])
1113   {
1114     scale[1] = scale[1] / (this->InitialBounds[3] - this->InitialBounds[2]);
1115   }
1116   scale[2] = vtkMath::Norm(scaleVec[2]);
1117   if (this->InitialBounds[5] != this->InitialBounds[4])
1118   {
1119     scale[2] = scale[2] / (this->InitialBounds[5] - this->InitialBounds[4]);
1120   }
1121   t->Scale(scale[0], scale[1], scale[2]);
1122 
1123   // Add back in the contribution due to non-origin center
1124   t->Translate(-InitialCenter[0], -InitialCenter[1], -InitialCenter[2]);
1125 }
1126 
1127 //------------------------------------------------------------------------------
SetTransform(vtkTransform * t)1128 void vtkBoxRepresentation::SetTransform(vtkTransform* t)
1129 {
1130   if (!t)
1131   {
1132     vtkErrorMacro(<< "vtkTransform t must be non-nullptr");
1133     return;
1134   }
1135 
1136   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
1137   double xIn[3];
1138   // make sure the transform is up-to-date before using it
1139   t->Update();
1140 
1141   // Position the eight points of the box and then update the
1142   // position of the other handles.
1143   double* bounds = this->InitialBounds;
1144 
1145   xIn[0] = bounds[0];
1146   xIn[1] = bounds[2];
1147   xIn[2] = bounds[4];
1148   t->InternalTransformPoint(xIn, pts);
1149 
1150   xIn[0] = bounds[1];
1151   xIn[1] = bounds[2];
1152   xIn[2] = bounds[4];
1153   t->InternalTransformPoint(xIn, pts + 3);
1154 
1155   xIn[0] = bounds[1];
1156   xIn[1] = bounds[3];
1157   xIn[2] = bounds[4];
1158   t->InternalTransformPoint(xIn, pts + 6);
1159 
1160   xIn[0] = bounds[0];
1161   xIn[1] = bounds[3];
1162   xIn[2] = bounds[4];
1163   t->InternalTransformPoint(xIn, pts + 9);
1164 
1165   xIn[0] = bounds[0];
1166   xIn[1] = bounds[2];
1167   xIn[2] = bounds[5];
1168   t->InternalTransformPoint(xIn, pts + 12);
1169 
1170   xIn[0] = bounds[1];
1171   xIn[1] = bounds[2];
1172   xIn[2] = bounds[5];
1173   t->InternalTransformPoint(xIn, pts + 15);
1174 
1175   xIn[0] = bounds[1];
1176   xIn[1] = bounds[3];
1177   xIn[2] = bounds[5];
1178   t->InternalTransformPoint(xIn, pts + 18);
1179 
1180   xIn[0] = bounds[0];
1181   xIn[1] = bounds[3];
1182   xIn[2] = bounds[5];
1183   t->InternalTransformPoint(xIn, pts + 21);
1184 
1185   this->PositionHandles();
1186 }
1187 
1188 //------------------------------------------------------------------------------
SetOutlineFaceWires(int newValue)1189 void vtkBoxRepresentation::SetOutlineFaceWires(int newValue)
1190 {
1191   if (this->OutlineFaceWires != newValue)
1192   {
1193     this->OutlineFaceWires = newValue;
1194     this->Modified();
1195     // the outline is dependent on this value, so we have to regen
1196     this->GenerateOutline();
1197   }
1198 }
1199 
1200 //------------------------------------------------------------------------------
SetOutlineCursorWires(int newValue)1201 void vtkBoxRepresentation::SetOutlineCursorWires(int newValue)
1202 {
1203   if (this->OutlineCursorWires != newValue)
1204   {
1205     this->OutlineCursorWires = newValue;
1206     this->Modified();
1207     // the outline is dependent on this value, so we have to regen
1208     this->GenerateOutline();
1209   }
1210 }
1211 
1212 //------------------------------------------------------------------------------
GenerateOutline()1213 void vtkBoxRepresentation::GenerateOutline()
1214 {
1215   // Whatever the case may be, we have to reset the Lines of the
1216   // OutlinePolyData (i.e. nuke all current line data)
1217   vtkCellArray* cells = this->OutlinePolyData->GetLines();
1218   cells->Reset();
1219   cells->Modified();
1220 
1221   // Now the outline lines
1222   if (!this->OutlineFaceWires && !this->OutlineCursorWires)
1223   {
1224     return;
1225   }
1226 
1227   vtkIdType pts[2];
1228 
1229   if (this->OutlineFaceWires)
1230   {
1231     pts[0] = 0;
1232     pts[1] = 7; // the -x face
1233     cells->InsertNextCell(2, pts);
1234     pts[0] = 3;
1235     pts[1] = 4;
1236     cells->InsertNextCell(2, pts);
1237     pts[0] = 1;
1238     pts[1] = 6; // the +x face
1239     cells->InsertNextCell(2, pts);
1240     pts[0] = 2;
1241     pts[1] = 5;
1242     cells->InsertNextCell(2, pts);
1243     if (!this->TwoPlaneMode)
1244     {
1245       pts[0] = 1;
1246       pts[1] = 4; // the -y face
1247       cells->InsertNextCell(2, pts);
1248       pts[0] = 0;
1249       pts[1] = 5;
1250       cells->InsertNextCell(2, pts);
1251       pts[0] = 3;
1252       pts[1] = 6; // the +y face
1253       cells->InsertNextCell(2, pts);
1254       pts[0] = 2;
1255       pts[1] = 7;
1256       cells->InsertNextCell(2, pts);
1257       pts[0] = 0;
1258       pts[1] = 2; // the -z face
1259       cells->InsertNextCell(2, pts);
1260       pts[0] = 1;
1261       pts[1] = 3;
1262       cells->InsertNextCell(2, pts);
1263       pts[0] = 4;
1264       pts[1] = 6; // the +Z face
1265       cells->InsertNextCell(2, pts);
1266       pts[0] = 5;
1267       pts[1] = 7;
1268       cells->InsertNextCell(2, pts);
1269     }
1270   }
1271   if (this->OutlineCursorWires)
1272   {
1273     pts[0] = 8;
1274     pts[1] = 9; // the x cursor line
1275     cells->InsertNextCell(2, pts);
1276     if (!this->TwoPlaneMode)
1277     {
1278       pts[0] = 10;
1279       pts[1] = 11; // the y cursor line
1280       cells->InsertNextCell(2, pts);
1281       pts[0] = 12;
1282       pts[1] = 13; // the z cursor line
1283       cells->InsertNextCell(2, pts);
1284     }
1285   }
1286   this->OutlinePolyData->Modified();
1287   if (this->OutlineProperty)
1288   {
1289     this->OutlineProperty->SetRepresentationToWireframe();
1290     this->SelectedOutlineProperty->SetRepresentationToWireframe();
1291   }
1292 }
1293 
1294 //------------------------------------------------------------------------------
ComputeInteractionState(int X,int Y,int modify)1295 int vtkBoxRepresentation::ComputeInteractionState(int X, int Y, int modify)
1296 {
1297   // Okay, we can process this. Try to pick handles first;
1298   // if no handles picked, then pick the bounding box.
1299   if (!this->Renderer || !this->Renderer->IsInViewport(X, Y))
1300   {
1301     this->InteractionState = vtkBoxRepresentation::Outside;
1302     return this->InteractionState;
1303   }
1304 
1305   // Try and pick a handle first
1306   this->LastPicker = nullptr;
1307   this->CurrentHandle = nullptr;
1308 
1309   vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
1310 
1311   if (path != nullptr)
1312   {
1313     this->ValidPick = 1;
1314     this->LastPicker = this->HandlePicker;
1315     this->CurrentHandle = reinterpret_cast<vtkActor*>(path->GetFirstNode()->GetViewProp());
1316     if (this->CurrentHandle == this->Handle[0])
1317     {
1318       this->InteractionState = vtkBoxRepresentation::MoveF0;
1319     }
1320     else if (this->CurrentHandle == this->Handle[1])
1321     {
1322       this->InteractionState = vtkBoxRepresentation::MoveF1;
1323     }
1324     else if (this->CurrentHandle == this->Handle[2])
1325     {
1326       this->InteractionState = vtkBoxRepresentation::MoveF2;
1327     }
1328     else if (this->CurrentHandle == this->Handle[3])
1329     {
1330       this->InteractionState = vtkBoxRepresentation::MoveF3;
1331     }
1332     else if (this->CurrentHandle == this->Handle[4])
1333     {
1334       this->InteractionState = vtkBoxRepresentation::MoveF4;
1335     }
1336     else if (this->CurrentHandle == this->Handle[5])
1337     {
1338       this->InteractionState = vtkBoxRepresentation::MoveF5;
1339     }
1340     else if (this->CurrentHandle == this->Handle[6])
1341     {
1342       this->InteractionState = vtkBoxRepresentation::Translating;
1343     }
1344   }
1345   else // see if the hex is picked
1346   {
1347     path = this->GetAssemblyPath(X, Y, 0., this->HexPicker);
1348 
1349     if (path != nullptr)
1350     {
1351       this->LastPicker = this->HexPicker;
1352       this->ValidPick = 1;
1353       if (!modify)
1354       {
1355         this->InteractionState = vtkBoxRepresentation::Rotating;
1356       }
1357       else
1358       {
1359         this->CurrentHandle = this->Handle[6];
1360         this->InteractionState = vtkBoxRepresentation::Translating;
1361       }
1362     }
1363     else
1364     {
1365       this->InteractionState = vtkBoxRepresentation::Outside;
1366     }
1367   }
1368 
1369   return this->InteractionState;
1370 }
1371 
ComputeComplexInteractionState(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void * calldata,int)1372 int vtkBoxRepresentation::ComputeComplexInteractionState(
1373   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void* calldata, int)
1374 {
1375   this->InteractionState = vtkBoxRepresentation::Outside;
1376 
1377   vtkEventData* edata = static_cast<vtkEventData*>(calldata);
1378   vtkEventDataDevice3D* edd = edata->GetAsEventDataDevice3D();
1379   if (edd)
1380   {
1381     double pos[3];
1382     edd->GetWorldPosition(pos);
1383 
1384     // Try and pick a handle first
1385     this->LastPicker = nullptr;
1386     this->CurrentHandle = nullptr;
1387 
1388     vtkAssemblyPath* path = this->GetAssemblyPath3DPoint(pos, this->HandlePicker);
1389 
1390     if (path != nullptr)
1391     {
1392       this->ValidPick = 1;
1393       this->LastPicker = this->HandlePicker;
1394       this->CurrentHandle = reinterpret_cast<vtkActor*>(path->GetFirstNode()->GetViewProp());
1395       if (this->CurrentHandle == this->Handle[0])
1396       {
1397         this->InteractionState = vtkBoxRepresentation::MoveF0;
1398       }
1399       else if (this->CurrentHandle == this->Handle[1])
1400       {
1401         this->InteractionState = vtkBoxRepresentation::MoveF1;
1402       }
1403       else if (this->CurrentHandle == this->Handle[2])
1404       {
1405         this->InteractionState = vtkBoxRepresentation::MoveF2;
1406       }
1407       else if (this->CurrentHandle == this->Handle[3])
1408       {
1409         this->InteractionState = vtkBoxRepresentation::MoveF3;
1410       }
1411       else if (this->CurrentHandle == this->Handle[4])
1412       {
1413         this->InteractionState = vtkBoxRepresentation::MoveF4;
1414       }
1415       else if (this->CurrentHandle == this->Handle[5])
1416       {
1417         this->InteractionState = vtkBoxRepresentation::MoveF5;
1418       }
1419       else if (this->CurrentHandle == this->Handle[6])
1420       {
1421         this->InteractionState = vtkBoxRepresentation::Translating;
1422       }
1423     }
1424     else // see if the hex is picked
1425     {
1426       path = this->GetAssemblyPath3DPoint(pos, this->HexPicker);
1427 
1428       if (path != nullptr)
1429       {
1430         this->LastPicker = this->HexPicker;
1431         this->ValidPick = 1;
1432         this->CurrentHandle = this->Handle[6];
1433         this->InteractionState = vtkBoxRepresentation::Translating;
1434       }
1435     }
1436   }
1437 
1438   return this->InteractionState;
1439 }
1440 
1441 //------------------------------------------------------------------------------
SetInteractionState(int state)1442 void vtkBoxRepresentation::SetInteractionState(int state)
1443 {
1444   // Clamp to allowable values
1445   state = (state < vtkBoxRepresentation::Outside
1446       ? vtkBoxRepresentation::Outside
1447       : (state > vtkBoxRepresentation::Scaling ? vtkBoxRepresentation::Scaling : state));
1448 
1449   // Depending on state, highlight appropriate parts of representation
1450   int handle;
1451   this->InteractionState = state;
1452   switch (state)
1453   {
1454     case vtkBoxRepresentation::MoveF0:
1455     case vtkBoxRepresentation::MoveF1:
1456     case vtkBoxRepresentation::MoveF2:
1457     case vtkBoxRepresentation::MoveF3:
1458     case vtkBoxRepresentation::MoveF4:
1459     case vtkBoxRepresentation::MoveF5:
1460       this->HighlightOutline(0);
1461       handle = this->HighlightHandle(this->CurrentHandle);
1462       this->HighlightFace(handle);
1463       break;
1464     case vtkBoxRepresentation::Rotating:
1465       this->HighlightOutline(0);
1466       this->HighlightHandle(nullptr);
1467       this->HighlightFace(this->HexPicker->GetCellId());
1468       break;
1469     case vtkBoxRepresentation::Translating:
1470     case vtkBoxRepresentation::Scaling:
1471       this->HighlightOutline(1);
1472       this->HighlightHandle(this->Handle[6]);
1473       this->HighlightFace(-1);
1474       break;
1475     default:
1476       this->HighlightOutline(0);
1477       this->HighlightHandle(nullptr);
1478       this->HighlightFace(-1);
1479   }
1480 }
1481 
1482 //------------------------------------------------------------------------------
GetBounds()1483 double* vtkBoxRepresentation::GetBounds()
1484 {
1485   this->BuildRepresentation();
1486   this->BoundingBox->SetBounds(this->HexActor->GetBounds());
1487   return this->BoundingBox->GetBounds();
1488 }
1489 
1490 //------------------------------------------------------------------------------
BuildRepresentation()1491 void vtkBoxRepresentation::BuildRepresentation()
1492 {
1493   // Rebuild only if necessary
1494   if (this->GetMTime() > this->BuildTime ||
1495     (this->Renderer && this->Renderer->GetVTKWindow() &&
1496       (this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime ||
1497         this->Renderer->GetActiveCamera()->GetMTime() > this->BuildTime)))
1498   {
1499     this->SizeHandles();
1500     this->BuildTime.Modified();
1501   }
1502 }
1503 
1504 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * w)1505 void vtkBoxRepresentation::ReleaseGraphicsResources(vtkWindow* w)
1506 {
1507   this->HexActor->ReleaseGraphicsResources(w);
1508   this->HexOutline->ReleaseGraphicsResources(w);
1509   this->HexFace->ReleaseGraphicsResources(w);
1510   // render the handles
1511   for (int j = 0; j < 7; j++)
1512   {
1513     this->Handle[j]->ReleaseGraphicsResources(w);
1514   }
1515 }
1516 
1517 //------------------------------------------------------------------------------
RenderOpaqueGeometry(vtkViewport * v)1518 int vtkBoxRepresentation::RenderOpaqueGeometry(vtkViewport* v)
1519 {
1520   int count = 0;
1521   this->BuildRepresentation();
1522 
1523   this->HexActor->SetPropertyKeys(this->GetPropertyKeys());
1524   this->HexOutline->SetPropertyKeys(this->GetPropertyKeys());
1525   this->HexFace->SetPropertyKeys(this->GetPropertyKeys());
1526 
1527   count += this->HexActor->RenderOpaqueGeometry(v);
1528   count += this->HexOutline->RenderOpaqueGeometry(v);
1529   count += this->HexFace->RenderOpaqueGeometry(v);
1530   for (int j = 0; j < 7; j++)
1531   {
1532     if (this->Handle[j]->GetVisibility())
1533     {
1534       this->Handle[j]->SetPropertyKeys(this->GetPropertyKeys());
1535       count += this->Handle[j]->RenderOpaqueGeometry(v);
1536     }
1537   }
1538 
1539   return count;
1540 }
1541 
1542 //------------------------------------------------------------------------------
RenderTranslucentPolygonalGeometry(vtkViewport * v)1543 int vtkBoxRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport* v)
1544 {
1545   int count = 0;
1546   this->BuildRepresentation();
1547 
1548   this->HexActor->SetPropertyKeys(this->GetPropertyKeys());
1549   this->HexOutline->SetPropertyKeys(this->GetPropertyKeys());
1550   this->HexFace->SetPropertyKeys(this->GetPropertyKeys());
1551 
1552   count += this->HexActor->RenderTranslucentPolygonalGeometry(v);
1553   count += this->HexOutline->RenderTranslucentPolygonalGeometry(v);
1554   count += this->HexFace->RenderTranslucentPolygonalGeometry(v);
1555   // render the handles
1556   for (int j = 0; j < 7; j++)
1557   {
1558     if (this->Handle[j]->GetVisibility())
1559     {
1560       this->Handle[j]->SetPropertyKeys(this->GetPropertyKeys());
1561       count += this->Handle[j]->RenderTranslucentPolygonalGeometry(v);
1562     }
1563   }
1564   return count;
1565 }
1566 
1567 //------------------------------------------------------------------------------
HasTranslucentPolygonalGeometry()1568 vtkTypeBool vtkBoxRepresentation::HasTranslucentPolygonalGeometry()
1569 {
1570   int result = 0;
1571   this->BuildRepresentation();
1572 
1573   result |= this->HexActor->HasTranslucentPolygonalGeometry();
1574   result |= this->HexOutline->HasTranslucentPolygonalGeometry();
1575 
1576   // If the face is not selected, we are not really rendering translucent faces,
1577   // hence don't bother taking it's opacity into consideration.
1578   // Look at BUG #7301.
1579   if (this->HexFace->GetProperty() == this->SelectedFaceProperty)
1580   {
1581     result |= this->HexFace->HasTranslucentPolygonalGeometry();
1582   }
1583 
1584   // render the handles
1585   for (int j = 0; j < 7; j++)
1586   {
1587     result |= this->Handle[j]->HasTranslucentPolygonalGeometry();
1588   }
1589 
1590   return result;
1591 }
1592 
1593 #define VTK_AVERAGE(a, b, c)                                                                       \
1594   c[0] = (a[0] + b[0]) / 2.0;                                                                      \
1595   c[1] = (a[1] + b[1]) / 2.0;                                                                      \
1596   c[2] = (a[2] + b[2]) / 2.0;
1597 
1598 //------------------------------------------------------------------------------
PositionHandles()1599 void vtkBoxRepresentation::PositionHandles()
1600 {
1601   double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
1602   double* p0 = pts;
1603   double* p1 = pts + 3 * 1;
1604   double* p2 = pts + 3 * 2;
1605   double* p3 = pts + 3 * 3;
1606   // double *p4 = pts + 3*4;
1607   double* p5 = pts + 3 * 5;
1608   double* p6 = pts + 3 * 6;
1609   double* p7 = pts + 3 * 7;
1610   double x[3];
1611 
1612   VTK_AVERAGE(p0, p7, x);
1613   this->Points->SetPoint(8, x);
1614   VTK_AVERAGE(p1, p6, x);
1615   this->Points->SetPoint(9, x);
1616   VTK_AVERAGE(p0, p5, x);
1617   this->Points->SetPoint(10, x);
1618   VTK_AVERAGE(p2, p7, x);
1619   this->Points->SetPoint(11, x);
1620   VTK_AVERAGE(p1, p3, x);
1621   this->Points->SetPoint(12, x);
1622   VTK_AVERAGE(p5, p7, x);
1623   this->Points->SetPoint(13, x);
1624   VTK_AVERAGE(p0, p6, x);
1625   this->Points->SetPoint(14, x);
1626 
1627   for (int i = 0; i < 7; ++i)
1628   {
1629     this->HandleGeometry[i]->SetCenter(this->Points->GetPoint(8 + i));
1630   }
1631 
1632   for (int i = 0; i < 6; ++i)
1633   {
1634     this->Planes[i]->SetOrigin(this->Points->GetPoint(8 + i));
1635     int mix = 2 * (i % 2);
1636     vtkVector3d pp1(this->Points->GetPoint(8 + i));
1637     vtkVector3d pp2(this->Points->GetPoint(9 + i - mix));
1638     pp2 = pp2 - pp1;
1639     pp2.Normalize();
1640     this->Planes[i]->SetNormal(pp2.GetData());
1641   }
1642 
1643   this->Points->GetData()->Modified();
1644   this->HexFacePolyData->Modified();
1645   this->HexPolyData->Modified();
1646   this->GenerateOutline();
1647 }
1648 #undef VTK_AVERAGE
1649 
1650 //------------------------------------------------------------------------------
HandlesOn()1651 void vtkBoxRepresentation::HandlesOn()
1652 {
1653   if (this->TwoPlaneMode)
1654   {
1655     this->Handle[0]->VisibilityOn();
1656     this->Handle[1]->VisibilityOn();
1657     this->Handle[6]->VisibilityOn();
1658   }
1659   else
1660   {
1661     for (int i = 0; i < 7; i++)
1662     {
1663       this->Handle[i]->VisibilityOn();
1664     }
1665   }
1666 }
1667 
1668 //------------------------------------------------------------------------------
HandlesOff()1669 void vtkBoxRepresentation::HandlesOff()
1670 {
1671   for (int i = 0; i < 7; i++)
1672   {
1673     this->Handle[i]->VisibilityOff();
1674   }
1675 }
1676 
1677 //------------------------------------------------------------------------------
SizeHandles()1678 void vtkBoxRepresentation::SizeHandles()
1679 {
1680   double* center = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(3 * 14);
1681   double radius = this->vtkWidgetRepresentation::SizeHandlesInPixels(1.5, center);
1682   for (int i = 0; i < 7; i++)
1683   {
1684     this->HandleGeometry[i]->SetRadius(radius);
1685   }
1686 }
1687 
1688 //------------------------------------------------------------------------------
HighlightHandle(vtkProp * prop)1689 int vtkBoxRepresentation::HighlightHandle(vtkProp* prop)
1690 {
1691   // first unhighlight anything picked
1692   this->HighlightOutline(0);
1693   if (this->CurrentHandle)
1694   {
1695     this->CurrentHandle->SetProperty(this->HandleProperty);
1696   }
1697 
1698   this->CurrentHandle = static_cast<vtkActor*>(prop);
1699 
1700   if (this->CurrentHandle)
1701   {
1702     this->CurrentHandle->SetProperty(this->SelectedHandleProperty);
1703     for (int i = 0; i < 6; i++) // find attached face
1704     {
1705       if (this->CurrentHandle == this->Handle[i])
1706       {
1707         return i;
1708       }
1709     }
1710   }
1711 
1712   if (this->CurrentHandle == this->Handle[6])
1713   {
1714     this->HighlightOutline(1);
1715     return 6;
1716   }
1717 
1718   return -1;
1719 }
1720 
1721 //------------------------------------------------------------------------------
HighlightFace(int cellId)1722 void vtkBoxRepresentation::HighlightFace(int cellId)
1723 {
1724   if (cellId >= 0)
1725   {
1726     vtkIdType npts;
1727     const vtkIdType* pts;
1728     vtkCellArray* cells = this->HexFacePolyData->GetPolys();
1729     this->HexPolyData->GetCellPoints(cellId, npts, pts);
1730     this->HexFacePolyData->Modified();
1731     cells->ReplaceCellAtId(0, npts, pts);
1732     cells->Modified();
1733     this->CurrentHexFace = cellId;
1734     this->HexFace->SetProperty(this->SelectedFaceProperty);
1735     if (!this->CurrentHandle)
1736     {
1737       this->CurrentHandle = this->HexFace;
1738     }
1739   }
1740   else
1741   {
1742     this->HexFace->SetProperty(this->FaceProperty);
1743     this->CurrentHexFace = -1;
1744   }
1745 }
1746 
1747 //------------------------------------------------------------------------------
HighlightOutline(int highlight)1748 void vtkBoxRepresentation::HighlightOutline(int highlight)
1749 {
1750   if (highlight)
1751   {
1752     this->HexActor->SetProperty(this->SelectedOutlineProperty);
1753     this->HexOutline->SetProperty(this->SelectedOutlineProperty);
1754   }
1755   else
1756   {
1757     this->HexActor->SetProperty(this->OutlineProperty);
1758     this->HexOutline->SetProperty(this->OutlineProperty);
1759   }
1760 }
1761 
1762 //------------------------------------------------------------------------------
RegisterPickers()1763 void vtkBoxRepresentation::RegisterPickers()
1764 {
1765   vtkPickingManager* pm = this->GetPickingManager();
1766   if (!pm)
1767   {
1768     return;
1769   }
1770   pm->AddPicker(this->HandlePicker, this);
1771   pm->AddPicker(this->HexPicker, this);
1772 }
1773 
1774 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1775 void vtkBoxRepresentation::PrintSelf(ostream& os, vtkIndent indent)
1776 {
1777   this->Superclass::PrintSelf(os, indent);
1778 
1779   double* bounds = this->InitialBounds;
1780   os << indent << "Initial Bounds: "
1781      << "(" << bounds[0] << "," << bounds[1] << ") "
1782      << "(" << bounds[2] << "," << bounds[3] << ") "
1783      << "(" << bounds[4] << "," << bounds[5] << ")\n";
1784 
1785   if (this->HandleProperty)
1786   {
1787     os << indent << "Handle Property: " << this->HandleProperty << "\n";
1788   }
1789   else
1790   {
1791     os << indent << "Handle Property: (none)\n";
1792   }
1793   if (this->SelectedHandleProperty)
1794   {
1795     os << indent << "Selected Handle Property: " << this->SelectedHandleProperty << "\n";
1796   }
1797   else
1798   {
1799     os << indent << "SelectedHandle Property: (none)\n";
1800   }
1801 
1802   if (this->FaceProperty)
1803   {
1804     os << indent << "Face Property: " << this->FaceProperty << "\n";
1805   }
1806   else
1807   {
1808     os << indent << "Face Property: (none)\n";
1809   }
1810   if (this->SelectedFaceProperty)
1811   {
1812     os << indent << "Selected Face Property: " << this->SelectedFaceProperty << "\n";
1813   }
1814   else
1815   {
1816     os << indent << "Selected Face Property: (none)\n";
1817   }
1818 
1819   if (this->OutlineProperty)
1820   {
1821     os << indent << "Outline Property: " << this->OutlineProperty << "\n";
1822   }
1823   else
1824   {
1825     os << indent << "Outline Property: (none)\n";
1826   }
1827   if (this->SelectedOutlineProperty)
1828   {
1829     os << indent << "Selected Outline Property: " << this->SelectedOutlineProperty << "\n";
1830   }
1831   else
1832   {
1833     os << indent << "Selected Outline Property: (none)\n";
1834   }
1835 
1836   os << indent << "Snap To Axes: " << (this->SnapToAxes ? "On\n" : "Off\n");
1837   os << indent << "Two Plane Mode: " << (this->TwoPlaneMode ? "On\n" : "Off\n");
1838 
1839   os << indent << "Outline Face Wires: " << (this->OutlineFaceWires ? "On\n" : "Off\n");
1840   os << indent << "Outline Cursor Wires: " << (this->OutlineCursorWires ? "On\n" : "Off\n");
1841   os << indent << "Inside Out: " << (this->InsideOut ? "On\n" : "Off\n");
1842 }
1843