1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkQWidgetRepresentation.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 "vtkQWidgetRepresentation.h"
16 
17 #include "vtkActor.h"
18 #include "vtkCellPicker.h"
19 #include "vtkEventData.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkOpenGLRenderWindow.h"
22 #include "vtkOpenGLState.h"
23 #include "vtkOpenGLTexture.h"
24 #include "vtkPickingManager.h"
25 #include "vtkPlaneSource.h"
26 #include "vtkPolyDataMapper.h"
27 #include "vtkProperty.h"
28 #include "vtkQWidgetTexture.h"
29 #include "vtkRenderer.h"
30 #include "vtkVectorOperators.h"
31 #include <QtWidgets/QWidget>
32 
33 #include "vtk_glew.h"
34 
35 vtkStandardNewMacro(vtkQWidgetRepresentation);
36 
37 //------------------------------------------------------------------------------
vtkQWidgetRepresentation()38 vtkQWidgetRepresentation::vtkQWidgetRepresentation()
39 {
40   this->PlaneSource = vtkPlaneSource::New();
41   this->PlaneSource->SetOutputPointsPrecision(vtkAlgorithm::DOUBLE_PRECISION);
42 
43   this->PlaneMapper = vtkPolyDataMapper::New();
44   this->PlaneMapper->SetInputConnection(this->PlaneSource->GetOutputPort());
45 
46   this->QWidgetTexture = vtkQWidgetTexture::New();
47   this->PlaneTexture = vtkOpenGLTexture::New();
48   this->PlaneTexture->SetTextureObject(this->QWidgetTexture);
49 
50   this->PlaneActor = vtkActor::New();
51   this->PlaneActor->SetMapper(this->PlaneMapper);
52   this->PlaneActor->SetTexture(this->PlaneTexture);
53   this->PlaneActor->GetProperty()->SetAmbient(1.0);
54   this->PlaneActor->GetProperty()->SetDiffuse(0.0);
55   this->PlaneActor->ForceOpaqueOn();
56 
57   // Define the point coordinates
58   double bounds[6];
59   bounds[0] = -0.5;
60   bounds[1] = 0.5;
61   bounds[2] = -0.5;
62   bounds[3] = 0.5;
63   bounds[4] = -0.5;
64   bounds[5] = 0.5;
65 
66   // Initial creation of the widget, serves to initialize it
67   this->PlaceWidget(bounds);
68 
69   this->Picker = vtkCellPicker::New();
70   this->Picker->SetTolerance(0.005);
71   this->Picker->AddPickList(this->PlaneActor);
72   this->Picker->PickFromListOn();
73 }
74 
75 //------------------------------------------------------------------------------
~vtkQWidgetRepresentation()76 vtkQWidgetRepresentation::~vtkQWidgetRepresentation()
77 {
78   this->PlaneSource->Delete();
79   this->PlaneMapper->Delete();
80   this->PlaneActor->Delete();
81   this->PlaneTexture->Delete();
82   this->QWidgetTexture->Delete();
83 
84   this->Picker->Delete();
85 }
86 
SetWidget(QWidget * w)87 void vtkQWidgetRepresentation::SetWidget(QWidget* w)
88 {
89   // just pass down to the QWidgetTexture
90   this->QWidgetTexture->SetWidget(w);
91   this->Modified();
92 }
93 
94 // see if the event hits the widget rep, if so set the WidgetCoordinates
95 // and move to Inside state
ComputeComplexInteractionState(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void * calldata,int)96 int vtkQWidgetRepresentation::ComputeComplexInteractionState(
97   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void* calldata, int)
98 {
99   vtkEventData* edata = static_cast<vtkEventData*>(calldata);
100   vtkEventDataDevice3D* edd = edata->GetAsEventDataDevice3D();
101   if (edd)
102   {
103     // compute intersection point using math, faster better
104     vtkVector3d origin;
105     this->PlaneSource->GetOrigin(origin.GetData());
106     vtkVector3d axis0;
107     this->PlaneSource->GetPoint1(axis0.GetData());
108     vtkVector3d axis1;
109     this->PlaneSource->GetPoint2(axis1.GetData());
110 
111     axis0 = axis0 - origin;
112     axis1 = axis1 - origin;
113 
114     vtkVector3d rpos;
115     edd->GetWorldPosition(rpos.GetData());
116     rpos = rpos - origin;
117 
118     vtkVector3d rdir;
119     edd->GetWorldDirection(rdir.GetData());
120 
121     double lengtha0 = vtkMath::Normalize(axis0.GetData());
122     double lengtha1 = vtkMath::Normalize(axis1.GetData());
123 
124     vtkVector3d pnorm;
125     pnorm = axis0.Cross(axis1);
126     pnorm.Normalize();
127     double dist = rpos.Dot(pnorm) / rdir.Dot(pnorm);
128     rpos = rpos - rdir * dist;
129     double wCoords[2] = { 0.0, 0.0 };
130     wCoords[0] = rpos.Dot(axis0) / lengtha0;
131     wCoords[1] = rpos.Dot(axis1) / lengtha1;
132 
133     if (wCoords[0] < 0.0 || wCoords[0] > 1.0 || wCoords[1] < 0.0 || wCoords[1] > 1.0)
134     {
135       this->InteractionState = vtkQWidgetRepresentation::Outside;
136       return this->InteractionState;
137     }
138 
139     // the ray hit the widget
140     this->ValidPick = 1;
141     this->InteractionState = vtkQWidgetRepresentation::Inside;
142 
143     QWidget* widget = this->QWidgetTexture->GetWidget();
144     this->WidgetCoordinates[0] = wCoords[0] * widget->width();
145     this->WidgetCoordinates[1] = wCoords[1] * widget->height();
146     this->WidgetCoordinates[1] = widget->height() - this->WidgetCoordinates[1];
147   }
148 
149   return this->InteractionState;
150 }
151 
152 //------------------------------------------------------------------------------
GetBounds()153 double* vtkQWidgetRepresentation::GetBounds()
154 {
155   this->BuildRepresentation();
156   return this->PlaneActor->GetBounds();
157 }
158 
159 //------------------------------------------------------------------------------
GetActors(vtkPropCollection * pc)160 void vtkQWidgetRepresentation::GetActors(vtkPropCollection* pc)
161 {
162   this->PlaneActor->GetActors(pc);
163 }
164 
165 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * w)166 void vtkQWidgetRepresentation::ReleaseGraphicsResources(vtkWindow* w)
167 {
168   this->PlaneActor->ReleaseGraphicsResources(w);
169   this->PlaneMapper->ReleaseGraphicsResources(w);
170   this->PlaneTexture->ReleaseGraphicsResources(w);
171 }
172 
173 //------------------------------------------------------------------------------
RenderOpaqueGeometry(vtkViewport * v)174 int vtkQWidgetRepresentation::RenderOpaqueGeometry(vtkViewport* v)
175 {
176   vtkInformation* info = this->GetPropertyKeys();
177   this->PlaneActor->SetPropertyKeys(info);
178 
179   vtkOpenGLRenderWindow* renWin = static_cast<vtkOpenGLRenderWindow*>(v->GetVTKWindow());
180   vtkOpenGLState* ostate = renWin->GetState();
181 
182   // always draw over the rest
183   ostate->vtkglDepthFunc(GL_ALWAYS);
184   int result = this->PlaneActor->RenderOpaqueGeometry(v);
185   ostate->vtkglDepthFunc(GL_LEQUAL);
186 
187   return result;
188 }
189 
190 //------------------------------------------------------------------------------
RenderTranslucentPolygonalGeometry(vtkViewport *)191 int vtkQWidgetRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport*)
192 {
193   return 0;
194 }
195 
196 //------------------------------------------------------------------------------
HasTranslucentPolygonalGeometry()197 vtkTypeBool vtkQWidgetRepresentation::HasTranslucentPolygonalGeometry()
198 {
199   return false;
200 }
201 
202 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)203 void vtkQWidgetRepresentation::PrintSelf(ostream& os, vtkIndent indent)
204 {
205   this->Superclass::PrintSelf(os, indent);
206 
207   // this->InteractionState is printed in superclass
208   // this is commented to avoid PrintSelf errors
209 }
210 
211 //------------------------------------------------------------------------------
PlaceWidget(double bds[6])212 void vtkQWidgetRepresentation::PlaceWidget(double bds[6])
213 {
214   this->PlaneSource->SetOrigin(bds[0], bds[2], bds[4]);
215   this->PlaneSource->SetPoint1(bds[1], bds[2], bds[4]);
216   this->PlaneSource->SetPoint2(bds[0], bds[2], bds[5]);
217 
218   this->ValidPick = 1; // since we have positioned the widget successfully
219 }
220 
221 //------------------------------------------------------------------------------
GetPolyDataAlgorithm()222 vtkPolyDataAlgorithm* vtkQWidgetRepresentation::GetPolyDataAlgorithm()
223 {
224   return this->PlaneSource;
225 }
226 
227 //------------------------------------------------------------------------------
UpdatePlacement()228 void vtkQWidgetRepresentation::UpdatePlacement() {}
229 
230 //------------------------------------------------------------------------------
BuildRepresentation()231 void vtkQWidgetRepresentation::BuildRepresentation()
232 {
233   // rep is always built via plane source and doesn't change
234 }
235 
236 //------------------------------------------------------------------------------
RegisterPickers()237 void vtkQWidgetRepresentation::RegisterPickers()
238 {
239   vtkPickingManager* pm = this->GetPickingManager();
240   if (!pm)
241   {
242     return;
243   }
244   pm->AddPicker(this->Picker, this);
245 }
246