Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DragTool.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
23 #include "hugin_config.h"
24 #include "panoinc_WX.h"
25 #include "panoinc.h"
26 
27 #include "DragTool.h"
28 #include "base_wx/CommandHistory.h"
29 #include "base_wx/PanoCommand.h"
31 
32 #include <math.h>
33 #include <wx/platform.h>
34 #ifdef __WXMAC__
35 #include <OpenGL/gl.h>
36 #else
37 #include <GL/gl.h>
38 #endif
39 
40 #include "GLPreviewFrame.h"
41 
43  : Tool(helper), drag_mode(drag_mode_normal)
44 {
45 }
46 
48 {
49  drag_mode = dmode;
50 }
51 
53 {
54  return drag_mode;
55 }
56 
57 //find Tr parameters shift based on polar coordinates
58 void DragTool::getTranslationShift(double &delta_x, double &delta_y)
59 {
60  double startx = atan(DEG_TO_RAD(start_coordinates.x));
61  double starty = atan(DEG_TO_RAD(start_coordinates.y));
62  double shiftx = atan(DEG_TO_RAD(shift_coordinates.x));
63  double shifty = atan(DEG_TO_RAD(shift_coordinates.y));
64  delta_x = shiftx - startx;
65  delta_y = shifty - starty;
66 }
67 
68 
70 {
71  drag_yaw = false; drag_pitch = false; drag_roll = false;
72  shift = false; control = false;
73  // register notifications
77  // a handy message for the user:
78  helper->SetStatusMessage(_("Drag to move images (optionally use shift to constrain), or roll with right-drag or Ctrl-drag"));
79 }
80 
81 void DragTool::MouseMoveEvent(double x, double y, wxMouseEvent & e)
82 {
84  x = pos.x;
85  y = pos.y;
86  if (drag_yaw || drag_pitch || drag_roll)
87  {
88 
89 
90  // how far are we moving?
91  if (drag_yaw || drag_pitch)
92  {
93 
94  double yaw, pitch;
96  pitch, x, y);
97  shift_coordinates.x = yaw;
98  shift_coordinates.y = pitch;
99  shift = e.m_shiftDown;
100  if (shift)
101  {
102  if (std::abs(shift_coordinates.x - start_coordinates.x)
103  < std::abs(shift_coordinates.y - start_coordinates.y))
104  {
106  helper->SetStatusMessage(_("Currently constrained to moving only pitch. Make a larger movement in the opposite direction to constrain to yaw."));
107 
108  } else {
110  helper->SetStatusMessage(_("Currently constrained to moving only yaw. Make a larger movement in the opposite direction to constrain to pitch."));
111  }
112  }
113 
114  }
115  if (drag_roll)
116  {
117  shift_angle = atan2(y - centre.y, x- centre.x) - start_angle;
118  }
119 
120  // move the selected images on the tempory copies for display.
121  // first calculate a matrix representing the transformation
122  if (drag_mode == drag_mode_mosaic) {
123  //if in mosaic drag mode do not adjust yaw and pitch, just roll
124  SetRotationMatrix(0,0,shift_angle, 0,0,0);
125  } else {
128  }
129 
130  std::map<unsigned int, ParamStore>::iterator i;
131  for (i = image_params.begin(); i != image_params.end(); ++i )
132  {
134  GetSrcImage(i->first);
135  double new_yaw, new_pitch, new_roll, new_TrX, new_TrY, new_TrZ, new_Tpy, new_Tpp;
136 
137  if (drag_mode == drag_mode_mosaic) {
138  //if in mosaic mode shift TrX and TrY parameters based on modified yaw and pitch
139  double shift_x, shift_y;
140  getTranslationShift(shift_x, shift_y);
141  i->second.TrX = img.getX() + shift_x;
142  i->second.TrY = img.getY() + shift_y;
143  }
144  i->second.Move(&rotation_matrix, new_yaw, new_pitch, new_roll, new_TrX, new_TrY, new_TrZ, new_Tpy, new_Tpp);
145  img.setX(new_TrX);
146  img.setY(new_TrY);
147  img.setZ(new_TrZ);
148  img.setTranslationPlaneYaw(new_Tpy);
149  img.setTranslationPlanePitch(new_Tpp);
150  img.setYaw(new_yaw);
151  img.setPitch(new_pitch);
152  img.setRoll(new_roll);
153  helper->GetViewStatePtr()->SetSrcImage(i->first, &img);
154  }
155 
156  // redraw
158  }
159 }
160 
161 void DragTool::MouseButtonEvent(wxMouseEvent &e)
162 {
163  if (e.ButtonDown())
164  {
165 
166  if (helper->IsMouseOverPano()) {
167 
168  control = e.m_controlDown;
169  shift = e.m_shiftDown;
170 
172 
173  std::set<unsigned int> images_under_mouse = helper->GetImageNumbersUnderMouse();
174  std::set<unsigned int>::iterator it;
175  for(it = images_under_mouse.begin() ; it != images_under_mouse.end() ; ++it) {
176  if (shift) {
178  } else {
180  }
181  }
182  return;
183 
184  }
185 
186  switch (e.GetButton())
187  {
188  // primary button
189  case wxMOUSE_BTN_LEFT:
190  // different things depending on modifier keys.
191 
192  // Either no key modifiers we care about, or shift.
193  // With shift we determine an adaptive constraint based on
194  // movement in both directions.
195  drag_yaw = true; drag_pitch = true;
196  break;
197  case wxMOUSE_BTN_RIGHT:
198  drag_roll = true;
199  break;
200  }
201  if (drag_roll)
202  {
203  // set centre and angle
205  centre.x, centre.y, 0.0, 0.0);
206  centre.x += 0.5;
207  centre.y += 0.5;
209  start_angle = atan2(angular.y, angular.x);
210  shift_angle = 0.0;
211  // we'll always rotate around the centre of the panorama.
212  start_coordinates.x = 0.0; start_coordinates.y = 0.0;
213  shift_coordinates.x = 0.0; shift_coordinates.y = 0.0;
214  helper->SetStatusMessage(_("Rotate around the centre to roll"));
215  }
216  if (drag_yaw || drag_pitch)
217  {
218  // We want to keep the point under the mouse pointer now under there
219  // wherever it goes. We'll calculate the roll, pitch, and yaw
220  // required to bring the centre to the point under the mouse. Then
221  // we rotate the panorama's images using the yaw and pitch of the
222  // movement. (Rotate start point to the centre, rotate by difference
223  // in yaw and pitch gained so far while dragging, then do the
224  // inverse of the rotation from start point to the centre on the
225  // result.
226  // set angles
227  double yaw, pitch;
230  pitch, mouse_pos.x, mouse_pos.y);
231  start_coordinates.x = yaw; start_coordinates.y = pitch;
232  shift_coordinates.x = yaw; shift_coordinates.y = pitch;
233  // provide a helpfull message to the user via the staus bar.
234  if (shift) {
235  helper->SetStatusMessage(_("Constrained drag: make a movement and it will be snapped to the yaw or pitch"));
236  } else {
237  helper->SetStatusMessage(_("Drag to move"));
238  }
239  }
240  if (drag_roll || drag_yaw || drag_pitch)
241  {
242  shift_angle = 0.0;
243  // record where the images are so we know what the difference is.
244  // Use the component the mouse points to instead of every image.
245  // Find the components
246 
247  /*
248  TODO: depending on state from the preview frame is not nice.
249  but this cannot be avoided in this case as the drag tool must depend on a central state,
250  which in this case is neither provided by the possibility of a central (parent) DragTool
251  nor a parent ToolHelper.
252  This is also the case for the identify tools, which inorder to interact with eachother
253  must rely on a central tool.
254  So the code at some point need to be refactored to provide central tool helper
255  and central tools, similarly as the ViewState is now central
256  compared to the VisualizationState which is specific to each visualization.
257  */
258  bool customDragging = helper->GetPreviewFrame()->individualDragging();
259  if (customDragging) {
261  std::set<unsigned int>::iterator i, end;
262  end = draging_images.end();
263  for (i = draging_images.begin(); i != end; ++i)
264  {
265  image_params[*i].Set(
267  }
268 
269  } else {
270 
271 
274  const size_t n = components.size();
275  // If there is only component, we can drag everything. Otherwise the
276  // component we want is the lowest numbered image under the mouse.
277  if (n == 1)
278  {
279  unsigned int imgs = helper->GetPanoramaPtr()->getNrOfImages();
280  draging_images.clear();
281  fill_set(draging_images, 0, imgs - 1);
282 
283  ViewState *view_state_ptr = helper->GetViewStatePtr();
284  for (unsigned int i = 0; i < imgs; i++)
285  {
286  image_params[i].Set(view_state_ptr->GetSrcImage(i));
287  };
288  } else
289  {
290  // multiple components or none at all.
291  if (n == 0 || helper->GetImageNumbersUnderMouse().empty())
292  {
293  // we can't drag nothing.
294  drag_roll = false; drag_yaw = false; drag_pitch = false;
295  return;
296  }
297 
298  // Find the component containing the topmost image under mouse
299  unsigned int img = *helper->GetImageNumbersUnderMouse().begin();
300  for (size_t component_index = 0;
301  component_index < n; component_index ++)
302  {
303  if (components[component_index].count(img))
304  {
305  // Found it, record which images and where they are.
306  draging_images = components[component_index];
307  std::set<unsigned int>::iterator i, end;
308  end = draging_images.end();
309  for (i = draging_images.begin(); i != end; ++i)
310  {
311  image_params[*i].Set(
313  }
314  break;
315  }
316  }
317  }
318  }
320  shift_angle,
322  }
323  }
324  } else {
325  // check this wasn't an attempt to drag empty space.
326  if (! (drag_pitch || drag_roll || drag_yaw)) return;
327 
328  // Finished draging images:
329  drag_yaw = false; drag_pitch = false; drag_roll = false;
330  // Apply the rotations permanently.
331  // find where the images end up.
332  std::vector<HuginBase::SrcPanoImage> src_images(draging_images.size() + 1);
333  std::map<unsigned int, ParamStore>::iterator i;
334  unsigned int count = 0;
335  for (i = image_params.begin(); i != image_params.end(); ++i)
336  {
337  double nyaw, npitch, nroll, nx, ny, nz, npy, npp;
338  i->second.Move(&rotation_matrix, nyaw, npitch, nroll, nx, ny, nz, npy, npp);
339  src_images[count] = helper->GetPanoramaPtr()->getSrcImage(i->first);
340  src_images[count].setX(nx);
341  src_images[count].setY(ny);
342  src_images[count].setZ(nz);
343  src_images[count].setTranslationPlaneYaw(npy);
344  src_images[count].setTranslationPlanePitch(npp);
345  src_images[count].setYaw(nyaw);
346  src_images[count].setPitch(npitch);
347  src_images[count].setRoll(nroll);
348  count++;
349  }
353  src_images)
354  );
355  // stop dragging
356  image_params.clear();
357 
358  helper->SetStatusMessage(_("Drag to move images (optionally use shift to constrain), or roll with right-drag or Ctrl-drag"));
359  }
360 }
361 
362 
363 
365 {
366  yaw = img->getYaw();
367  pitch = img->getPitch();
368  roll = img->getRoll();
369  TrX = img->getX();
370  TrY = img->getY();
371  TrZ = img->getZ();
372  Tpy = img->getTranslationPlaneYaw();
373  Tpp = img->getTranslationPlanePitch();
374 }
375 
377  double &yaw_out, double &pitch_out, double &roll_out,
378  double &TrX_out, double &TrY_out, double &TrZ_out,
379  double &Tpy_out, double &Tpp_out)
380 {
381  Matrix3 start, output_matrix;
382  // convert the location of this image to a matrix.
383  start.SetRotationPT(DEG_TO_RAD(yaw), DEG_TO_RAD(pitch), DEG_TO_RAD(roll));
384  // move it by the matrix specified.
385  output_matrix = *matrix * start;
386  // get the angles from the matrix
387  output_matrix.GetRotationPT(yaw_out, pitch_out, roll_out);
388  yaw_out = RAD_TO_DEG(yaw_out);
389  pitch_out = RAD_TO_DEG(pitch_out);
390  roll_out = RAD_TO_DEG(roll_out);
391 
392  if(TrX != 0.0 || TrY != 0.0 || TrZ != 0.0)
393  {
394  // rotate translation vector
395  Vector3 vecRot=matrix->Inverse().TransformVector(Vector3(TrZ, TrX, TrY));
396  TrX_out=vecRot.y;
397  TrY_out=vecRot.z;
398  TrZ_out=vecRot.x;
399  // rotate translation plane
400  start.SetRotationPT(DEG_TO_RAD(Tpy), DEG_TO_RAD(Tpp), 0.0);
401  output_matrix = (*matrix) * start;
402  double dummy;
403  output_matrix.GetRotationPT(Tpy_out, Tpp_out, dummy);
404  Tpy_out=RAD_TO_DEG(Tpy_out);
405  Tpp_out=RAD_TO_DEG(Tpp_out);
406  }
407  else
408  {
409  TrX_out=0;
410  TrY_out=0;
411  TrZ_out=0;
412  Tpy_out=0;
413  Tpp_out=0;
414  };
415 }
416 
417 void DragTool::SetRotationMatrix(double yaw_shift, double pitch_shift,
418  double roll_shift,
419  double yaw_start, double pitch_start,
420  double roll_start)
421 {
422  Matrix3 y1_mat, r_mat, y2_mat, p1_mat, p2_mat;
423  // rotates the start point to the centre
424  y1_mat.SetRotationPT(-DEG_TO_RAD(yaw_start), 0.0, 0.0);
425  p1_mat.SetRotationPT(0.0, DEG_TO_RAD(pitch_start), 0.0);
426  // rolls the image
427  r_mat.SetRotationPT(0.0, 0.0, roll_shift);
428  // rotates the centre to the destination point
429  p2_mat.SetRotationPT(0.0, -DEG_TO_RAD(pitch_shift), 0.0);
430  y2_mat.SetRotationPT(DEG_TO_RAD(yaw_shift), 0.0, 0.0);
431 
432  rotation_matrix = y2_mat * p2_mat * r_mat *p1_mat * y1_mat;
433 }
434 
436 {
437  // draw guide lines down the middle.
439  double width = (double) opts->getSize().width(),
440  height = (double) opts->getSize().height();
441  // Invert the color underneath.
443  glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
444  glEnable(GL_BLEND);
445  glColor3f(1.0, 1.0, 1.0);
446  glPushMatrix();
447  glTranslatef(-0.5, -0.5, -0.5);
448  glBegin(GL_LINES);
449  glVertex2f(width / 2.0, 0.0);
450  glVertex2f(width / 2.0, height);
451  glVertex2f(0.0, height / 2.0);
452  glVertex2f(width, height / 2.0);
453  glEnd();
454  // draw lines if we are dragging
455  if (drag_roll)
456  {
457  // when rolling, a line from the centre (where we rotate around) in the
458  // direction of the mouse pointer should help the user.
459  double distance = width * width + height * height,
460  angle = start_angle;
461  glPushMatrix();
462  glTranslatef(centre.x, centre.y, 0.0);
463  glBegin(GL_LINES);
464  // starting angle
465  glVertex2d(0.0, 0.0);
466  glVertex2f(distance * cos(angle), distance * sin(angle));
467  // angle now used
468  angle += shift_angle;
469  glVertex2d(0.0, 0.0);
470  glVertex2f(distance * cos(angle), distance * sin(angle));
471  glEnd();
472  glPopMatrix();
473  }
474  if (drag_pitch || drag_yaw)
475  {
476  // Draw a straight line in the spherical space, from the start point to
477  // under the mouse. It only appears straight when using a cylinderical
478  // projection or similar though, so we draw it as many line segments.
479  glBegin(GL_LINE_STRIP);
480  for (double t = 0.0; t <= 1.0; t+= 0.005)
481  {
482  double x, y, ti = 1.0 - t;
484  x, y,
487  glVertex2d(x, y);
488  }
489  glEnd();
490  }
491  glPopMatrix();
492  glDisable(GL_BLEND);
493  glEnable(GL_TEXTURE_2D);
494 }
495 
497 {
498 
499 }
500 
HuginBase::UIntSet GetDragGroupImages()
DragTool(ToolHelper *helper)
Definition: DragTool.cpp:42
update source images
Definition: PanoCommand.h:404
bool drag_roll
Definition: DragTool.h:83
double y
Definition: Vector3.h:47
implementation of huginApp Class
hugin_utils::FDiff2D GetMousePanoPosition()
Definition: ToolHelper.cpp:295
ViewState * GetViewStatePtr()
Definition: ToolHelper.cpp:305
DragMode drag_mode
Definition: DragTool.h:92
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
OutputProjectionInfo * GetProjectionInfo()
Definition: ViewState.cpp:278
void MouseMoveEvent(double x, double y, wxMouseEvent &e)
Notify when the mouse pointer has moved over the panorama preview.
Definition: DragTool.cpp:81
HuginBase::Panorama * GetPanoramaPtr()
Definition: ToolHelper.cpp:310
std::set< unsigned int > draging_images
Definition: DragTool.h:82
void DisableTexture(bool maskOnly=false)
void AddImageToDragGroup(unsigned int image_nr, bool update_check_box=true)
general : Matrix3 is a class for handling 3x3 Matrix manipulation.
Definition: Matrix3.h:37
include file for the hugin project
void GetRotationPT(double &Yaw, double &Pitch, double &Roll)
GetRotation in panotools style.
Definition: Matrix3.cpp:157
void NotifyMe(Event event, Tool *tool)
Definition: ToolHelper.cpp:315
std::set< unsigned int > GetImageNumbersUnderMouse()
Definition: ToolHelper.cpp:281
hugin_utils::FDiff2D start_coordinates
Definition: DragTool.h:85
Vector3 TransformVector(const Vector3 &V) const
transforms a vector
Definition: Matrix3.h:143
void SetRotationPT(double yaw, double pitch, double roll)
set rotation in panotools style, code adapted from Panotools-Script by Bruno Postle ...
Definition: Matrix3.cpp:110
void RemoveImageFromDragGroup(unsigned int image_nr, bool update_check_box=true)
std::vector< HuginBase::UIntSet > Components
stores the components of the graph
Definition: ImageGraph.h:50
VisualizationState * GetVisualizationStatePtr()
Definition: ToolHelper.cpp:300
HuginBase::PanoramaOptions * GetOptions()
Definition: ViewState.cpp:273
Matrix3 rotation_matrix
Definition: DragTool.h:87
ToolHelper * helper
The PreviewToolHelper that uses the same preview window and panorama as the tool should.
Definition: Tool.h:102
std::map< unsigned int, ParamStore > image_params
Definition: DragTool.h:81
void SetSrcImage(unsigned int image_nr, HuginBase::SrcPanoImage *new_img)
Definition: ViewState.cpp:176
bool control
Definition: DragTool.h:86
Definition: Tool.h:42
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
bool IsMouseOverPano()
Definition: ToolHelper.h:136
hugin_utils::FDiff2D centre
Definition: DragTool.h:85
bool AngularToImage(double &image_x, double &image_y, double yaw, double pitch)
TextureManager * GetTextureManager()
Definition: ViewState.h:104
void getTranslationShift(double &delta_x, double &delta_y)
Definition: DragTool.cpp:58
void Move(Matrix3 *matrix, double &yaw_out, double &pitch_out, double &roll_out, double &TrX_out, double &TrY_out, double &TrZ_out, double &Tpy_out, double &Tpp_out)
Definition: DragTool.cpp:376
static GlobalCmdHist & getInstance()
bool drag_yaw
Definition: DragTool.h:83
void ReallyAfterDrawImagesEvent()
Draw (using OpenGL) the overlays, e.g. crop highlights, guides.
Definition: DragTool.cpp:496
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
virtual OutputProjectionInfo * GetProjectionInfo()
Definition: ViewState.cpp:473
bool drag_pitch
Definition: DragTool.h:83
double start_angle
Definition: DragTool.h:84
void Activate()
Switch on a tool.
Definition: DragTool.cpp:69
void setDragMode(DragMode drag_mode)
Definition: DragTool.cpp:47
include file for the hugin project
#define RAD_TO_DEG(x)
Definition: hugin_math.h:45
Components GetComponents()
find all connected components
Definition: ImageGraph.cpp:101
Matrix3 Inverse() const
return inverse if it exists, otherwise identity
Definition: Matrix3.cpp:256
double z
Definition: Vector3.h:47
void SetRotationMatrix(double yaw_shift, double pitch_shift, double roll_shift, double yaw_start, double pitch_start, double roll_start)
Definition: DragTool.cpp:417
DragMode getDragMode()
Definition: DragTool.cpp:52
void SetStatusMessage(wxString message)
Definition: ToolHelper.cpp:409
void MouseButtonEvent(wxMouseEvent &e)
Notify of a mouse button press on the panorama preview.
Definition: DragTool.cpp:161
void Set(HuginBase::SrcPanoImage *img)
Definition: DragTool.cpp:364
#define DEG_TO_RAD(x)
Definition: hugin_math.h:44
general : Vector3 is a class for handling 3D Vectors manipulation.
Definition: Vector3.h:43
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition: stl_utils.h:81
double x
x,y,z coordinates, 0 at the initialisation
Definition: Vector3.h:47
HuginBase::SrcPanoImage * GetSrcImage(unsigned int image_nr)
Definition: ViewState.cpp:283
All variables of a source image.
Definition: SrcPanoImage.h:194
Panorama image options.
hugin_utils::FDiff2D shift_coordinates
Definition: DragTool.h:85
vigra::Size2D getSize() const
get size of output image
bool shift
Definition: DragTool.h:86
void ReallyAfterDrawImagesEvent()
Draw (using OpenGL) the overlays, e.g. crop highlights, guides.
Definition: DragTool.cpp:435
GLPreviewFrame * GetPreviewFrame()
Definition: ToolHelper.h:139
double shift_angle
Definition: DragTool.h:84
bool ImageToAngular(double &yaw, double &pitch, double image_x, double image_y)
class to work with images graphs created from a HuginBase::Panorama class it creates a graph based on...
Definition: ImageGraph.h:44