Fraxinus  17.12-rc4
An IGT application
cxCameraControl.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 /*
34  * cxCameraControl.cpp
35  *
36  * \date Oct 15, 2010
37  * \author christiana
38  */
39 #include "cxCameraControl.h"
40 
41 #include <QAction>
42 #include "vtkRenderer.h"
43 #include "vtkCamera.h"
44 #include "cxView.h"
45 #include <QDomNode>
46 #include "cxTypeConversions.h"
47 #include "cxLogger.h"
48 
49 namespace cx
50 {
51 
53 {
54 }
55 
57 {
58  mCamera = camera;
59 }
60 
62 {
63  if (!mCamera)
64  mCamera = vtkCameraPtr::New();
65  return mCamera;
66 }
67 
68 void CameraData::addTextElement(QDomNode parentNode, QString name, QString value) const
69 {
70  QDomDocument doc = parentNode.ownerDocument();
71  QDomElement node = doc.createElement(name);
72  node.appendChild(doc.createTextNode(value));
73  parentNode.appendChild(node);
74 }
75 
76 void CameraData::addXml(QDomNode dataNode) const
77 {
78  if (!mCamera)
79  return;
80 
81  this->addTextElement(dataNode, "position", qstring_cast(Vector3D(mCamera->GetPosition())));
82  this->addTextElement(dataNode, "focalPoint", qstring_cast(Vector3D(mCamera->GetFocalPoint())));
83  this->addTextElement(dataNode, "viewUp", qstring_cast(Vector3D(mCamera->GetViewUp())));
84  this->addTextElement(dataNode, "nearClip", qstring_cast(mCamera->GetClippingRange()[0]));
85  this->addTextElement(dataNode, "farClip", qstring_cast(mCamera->GetClippingRange()[1]));
86  this->addTextElement(dataNode, "parallelScale", qstring_cast(mCamera->GetParallelScale()));
87 }
88 
89 void CameraData::parseXml(QDomNode dataNode)
90 {
91  Vector3D position = Vector3D::fromString(dataNode.namedItem("position").toElement().text());
92  Vector3D focalPoint = Vector3D::fromString(dataNode.namedItem("focalPoint").toElement().text());
93  Vector3D viewUp = Vector3D::fromString(dataNode.namedItem("viewUp").toElement().text());
94  double nearClip = dataNode.namedItem("nearClip").toElement().text().toDouble();
95  double farClip = dataNode.namedItem("farClip").toElement().text().toDouble();
96  double parallelScale = dataNode.namedItem("parallelScale").toElement().text().toDouble();
97 
98  if (similar(viewUp.length(), 0.0))
99  return; // ignore reading if undefined data
100  double LARGE_NUMBER = 1.0E6; // corresponding to a distance of 1km - unphysical for human-sized data
101  if ((position-focalPoint).length() > LARGE_NUMBER)
102  return;
103  if (focalPoint.length() > LARGE_NUMBER)
104  return;
105  if (fabs(parallelScale) > LARGE_NUMBER)
106  return;
107 
108  this->getCamera();
109 
110  mCamera->SetClippingRange(nearClip, farClip);
111  mCamera->SetPosition(position.begin());
112  mCamera->SetFocalPoint(focalPoint.begin());
113  mCamera->ComputeViewPlaneNormal();
114  mCamera->SetViewUp(viewUp.begin());
115  mCamera->SetParallelScale(parallelScale);
116 }
117 
121 
122 
124  QObject(parent),
125  mSuperiorViewAction(NULL),
126  mAnteriorViewAction(NULL)
127 {
128 }
129 
131 {
132 }
133 
134 /*Move the camera focus to p_r. Keep the view direction and distance constant
135  * (i.e. keep pos of camera constant relative to focus).
136  *
137  */
139 {
140  vtkCameraPtr camera = this->getCamera();
141  if (!camera)
142  return;
143 
144  Vector3D f(camera->GetFocalPoint());
145  Vector3D p(camera->GetPosition());
146  Vector3D delta = p_r - f;
147  f += delta;
148  p += delta;
149  camera->SetFocalPoint(f.begin());
150  camera->SetPosition(p.begin());
151 }
152 
154 {
155  if(mSuperiorViewAction)
156  mSuperiorViewAction->trigger();
157 }
158 
160 {
161  if(mAnteriorViewAction)
162  mAnteriorViewAction->trigger();
163 }
164 
166 {
167  QActionGroup* group = new QActionGroup(this);
168  mAnteriorViewAction = this->addStandard3DViewAction("A", "Anterior View", Vector3D(0, 1, 0), group);
169  this->addStandard3DViewAction("P", "Posterior View", Vector3D(0, -1, 0), group);
170  mSuperiorViewAction = this->addStandard3DViewAction("S", "Superior View", Vector3D(0, 0, -1), group);
171  this->addStandard3DViewAction("I", "Inferior View", Vector3D(0, 0, 1), group);
172  this->addStandard3DViewAction("L", "Left View", Vector3D(-1, 0, 0), group);
173  this->addStandard3DViewAction("R", "Right View", Vector3D(1, 0, 0), group);
174  this->addStandard3DViewAction("O", "Orthogonal View", Vector3D(-1, 1, -1).normal(), group);
175  return group;
176 }
177 
180 QAction* CameraControl::addStandard3DViewAction(QString caption, QString help, Vector3D viewDirection,
181  QActionGroup* group)
182 {
183  QAction* action = new QAction(help, group);
184  action->setStatusTip(help);
185  action->setWhatsThis(help);
186  action->setIcon(QIcon(":/icons/camera_view_" + caption + ".png"));
187  // QFont font;
188  // font.setBold(true);
189  // if (font.pointSize()>=0)
190  // font.setPointSize(font.pointSize()*1.5);
191  // action->setFont(font);
192  action->setData(QVariant(qstring_cast(viewDirection)));
193  connect(action, &QAction::triggered, this, &CameraControl::setStandard3DViewActionSlot);
194  return action;
195 }
196 
198 {
199  this->setView(view);
200  if(view)
201  view->getRenderer()->ResetCameraClippingRange();
202 }
203 
205 {
206  mView = view;
207 }
208 
210 {
211  return mView;
212 }
213 
214 vtkRendererPtr CameraControl::getRenderer() const
215 {
216  if (!mView)
217  return vtkRendererPtr();
218  return mView->getRenderer();
219 }
220 vtkCameraPtr CameraControl::getCamera() const
221 {
222  if (!this->getRenderer())
223  return vtkCameraPtr();
224  return this->getRenderer()->GetActiveCamera();
225 }
226 
228 {
229  QAction* action = dynamic_cast<QAction*> (sender());
230  if (!action)
231  return;
232  Vector3D viewDirection = Vector3D::fromString(action->data().toString());
233 
234  vtkRendererPtr renderer = this->getRenderer();
235  if (!renderer)
236  return;
237  vtkCameraPtr camera = this->getCamera();
238 
239  renderer->ResetCamera();
240 
241  Vector3D focus(camera->GetFocalPoint());
242  Vector3D pos = focus - 500 * viewDirection;
243  Vector3D vup(0, 0, 1);
244  //Vector3D dir = (focus-direction).normal();
245 
246  Vector3D left = cross(vup, viewDirection);
247 // CX_LOG_CHANNEL_DEBUG("CA") << " cross(vup, viewDirection) " << cross(vup, viewDirection);
248  if (similar(left.length(), 0.0))
249  left = Vector3D(1, 0, 0);
250  vup = cross(viewDirection, left).normal();
251 
252 // CX_LOG_CHANNEL_DEBUG("CA") << "CameraControl::setStandard3DViewActionSlot()";
253 // CX_LOG_CHANNEL_DEBUG("CA") << " viewDirection " << viewDirection;
254 // CX_LOG_CHANNEL_DEBUG("CA") << " left " << left;
255 // CX_LOG_CHANNEL_DEBUG("CA") << " vup " << vup;
256 
257  camera->SetPosition(pos.begin());
258  camera->SetViewUp(vup.begin());
259 
260  renderer->ResetCamera(); // let vtk do the zooming base work
261  camera->Dolly(1.5); // zoom in a bit more than the default vtk value
262  renderer->ResetCameraClippingRange();
263 }
264 
265 } // namespace cx
QString qstring_cast(const T &val)
PlainObject normal() const
void setSuperiorView() const
vtkCameraPtr getCamera() const
void translateByFocusTo(Vector3D p_r)
boost::shared_ptr< class View > ViewPtr
Vector3D cross(const Vector3D &a, const Vector3D &b)
compute cross product of a and b.
Definition: cxVector3D.cpp:62
QActionGroup * createStandard3DViewActions()
vtkSmartPointer< class vtkRenderer > vtkRendererPtr
void setView(ViewPtr view)
void refreshView(ViewPtr view)
void parseXml(QDomNode dataNode)
load internal state info from dataNode
void addXml(QDomNode dataNode) const
store internal state info in dataNode
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
void setCamera(vtkCameraPtr camera)
void setAnteriorView() const
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
ViewPtr getView() const
CameraControl(QObject *parent=NULL)
void setStandard3DViewActionSlot()
vtkSmartPointer< class vtkCamera > vtkCameraPtr
Namespace for all CustusX production code.