DragTool.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00023 #include <config.h>
00024 #include "panoinc_WX.h"
00025 #include "panoinc.h"
00026 
00027 #include "DragTool.h"
00028 #include "base_wx/CommandHistory.h"
00029 #include "base_wx/PanoCommand.h"
00030 #include "algorithms/optimizer/ImageGraph.h"
00031 
00032 #include <math.h>
00033 #include <wx/platform.h>
00034 #ifdef __WXMAC__
00035 #include <OpenGL/gl.h>
00036 #else
00037 #include <GL/gl.h>
00038 #endif
00039 
00040 #include "GLPreviewFrame.h"
00041 
00042 DragTool::DragTool(ToolHelper *helper)
00043     : Tool(helper), drag_mode(drag_mode_normal)
00044 {
00045 }
00046 
00047 void DragTool::setDragMode(PreviewDragTool::DragMode dmode)
00048 {
00049         drag_mode = dmode;
00050 }
00051 
00052 DragTool::DragMode DragTool::getDragMode()
00053 {
00054         return drag_mode;
00055 }
00056 
00057 //find Tr parameters shift based on polar coordinates
00058 void DragTool::getTranslationShift(double &delta_x, double &delta_y)
00059 {
00060         double startx = atan(DEG_TO_RAD(start_coordinates.x));
00061         double starty = atan(DEG_TO_RAD(start_coordinates.y));
00062         double shiftx = atan(DEG_TO_RAD(shift_coordinates.x));
00063         double shifty = atan(DEG_TO_RAD(shift_coordinates.y));
00064         delta_x = shiftx - startx;
00065         delta_y = shifty - starty;
00066 }
00067 
00068 
00069 void DragTool::Activate()
00070 {
00071     drag_yaw = false; drag_pitch = false; drag_roll = false;
00072     shift = false; control = false;
00073     // register notifications
00074     helper->NotifyMe(PreviewToolHelper::MOUSE_MOVE, this);
00075     helper->NotifyMe(PreviewToolHelper::MOUSE_PRESS, this);
00076     helper->NotifyMe(PreviewToolHelper::REALLY_DRAW_OVER_IMAGES, this);
00077     // a handy message for the user:
00078     helper->SetStatusMessage(_("Drag to move images (optionally use shift to constrain), or roll with right-drag or Ctrl-drag."));
00079 }
00080 
00081 void DragTool::MouseMoveEvent(double x, double y, wxMouseEvent & e)
00082 {
00083     hugin_utils::FDiff2D pos = helper->GetMousePanoPosition();
00084     x = pos.x;
00085     y = pos.y;
00086     if (drag_yaw || drag_pitch || drag_roll)
00087     {
00088         
00089 
00090         // how far are we moving?
00091         if (drag_yaw || drag_pitch)
00092         {
00093 
00094             double yaw, pitch;
00095             helper->GetVisualizationStatePtr()->GetProjectionInfo()->ImageToAngular(yaw,
00096                                                pitch, x, y);
00097             shift_coordinates.x = yaw;
00098             shift_coordinates.y = pitch;
00099             shift = e.m_shiftDown;
00100             if (shift)
00101             {
00102                 if (std::abs(shift_coordinates.x - start_coordinates.x)
00103                     < std::abs(shift_coordinates.y - start_coordinates.y))
00104                 {
00105                     shift_coordinates.x = start_coordinates.x;
00106                     helper->SetStatusMessage(_("Currently constrained to moving only pitch. Make a larger movement in the opposite direction to constrain to yaw."));
00107                     
00108                 } else {
00109                     shift_coordinates.y = start_coordinates.y;
00110                     helper->SetStatusMessage(_("Currently constrained to moving only yaw. Make a larger movement in the opposite direction to constrain to pitch."));
00111                 }
00112             }
00113 
00114         }
00115         if (drag_roll)
00116         {
00117             shift_angle = atan2(y - centre.y, x- centre.x) - start_angle;
00118         }
00119 
00120         // move the selected images on the tempory copies for display.
00121         // first calculate a matrix representing the transformation
00122         if (drag_mode == drag_mode_mosaic) {
00123                 //if in mosaic drag mode do not adjust yaw and pitch, just roll
00124                         SetRotationMatrix(0,0,shift_angle, 0,0,0);
00125                 } else {
00126                     SetRotationMatrix(shift_coordinates.x, shift_coordinates.y, shift_angle,
00127                                       start_coordinates.x,  start_coordinates.y,  0.0);
00128                 }     
00129 
00130             std::map<unsigned int, ParamStore>::iterator i;
00131             for (i = image_params.begin(); i != image_params.end(); ++i )
00132             {
00133                 HuginBase::SrcPanoImage img = *helper->GetViewStatePtr()->
00134                                                               GetSrcImage(i->first);
00135             double new_yaw, new_pitch, new_roll, new_TrX, new_TrY, new_TrZ, new_Tpy, new_Tpp;
00136         
00137                 if (drag_mode == drag_mode_mosaic) {
00138                         //if in mosaic mode shift TrX and TrY parameters based on modified yaw and pitch
00139                         double shift_x, shift_y;
00140                                 getTranslationShift(shift_x, shift_y);
00141                                 i->second.TrX = img.getX() + shift_x;
00142                                 i->second.TrY = img.getY() + shift_y;
00143                         }
00144             i->second.Move(&rotation_matrix, new_yaw, new_pitch, new_roll, new_TrX, new_TrY, new_TrZ, new_Tpy, new_Tpp);
00145                 img.setX(new_TrX);
00146                 img.setY(new_TrY);
00147             img.setZ(new_TrZ);
00148             img.setTranslationPlaneYaw(new_Tpy);
00149             img.setTranslationPlanePitch(new_Tpp);
00150                 img.setYaw(new_yaw); 
00151                 img.setPitch(new_pitch); 
00152                 img.setRoll(new_roll);
00153                 helper->GetViewStatePtr()->SetSrcImage(i->first, &img);
00154             }
00155                           
00156         // redraw
00157         helper->GetVisualizationStatePtr()->Redraw();
00158     }
00159 }
00160 
00161 void DragTool::MouseButtonEvent(wxMouseEvent &e)
00162 {
00163     if (e.ButtonDown())
00164     {
00165 
00166         if (helper->IsMouseOverPano()) {
00167         
00168             control = e.m_controlDown;
00169             shift = e.m_shiftDown;
00170             
00171             if (control && (helper->GetPreviewFrame()->individualDragging())) {
00172                 
00173                 std::set<unsigned int> images_under_mouse = helper->GetImageNumbersUnderMouse();
00174                 std::set<unsigned int>::iterator it;
00175                 for(it = images_under_mouse.begin() ; it != images_under_mouse.end() ; ++it) {
00176                     if (shift) {
00177                         helper->GetPreviewFrame()->RemoveImageFromDragGroup(*it);
00178                     } else {
00179                         helper->GetPreviewFrame()->AddImageToDragGroup(*it);
00180                     }
00181                 }
00182                 return;
00183             
00184             }
00185             
00186             switch (e.GetButton())
00187             {
00188                 // primary button
00189                 case wxMOUSE_BTN_LEFT:
00190                     // different things depending on modifier keys.
00191 
00192                     // Either no key modifiers we care about, or shift.
00193                     // With shift we determine an adaptive constraint based on
00194                     // movement in both directions.
00195                     drag_yaw = true; drag_pitch = true;
00196                     break;
00197                 case wxMOUSE_BTN_RIGHT:
00198                     drag_roll = true;
00199                     break;
00200             }
00201             if (drag_roll)
00202             {
00203                 // set centre and angle
00204                 helper->GetViewStatePtr()->GetProjectionInfo()->AngularToImage(
00205                                                       centre.x, centre.y, 0.0, 0.0);
00206                 centre.x += 0.5;
00207                 centre.y += 0.5;
00208                 hugin_utils::FDiff2D angular = helper->GetMousePanoPosition() - centre;
00209                 start_angle = atan2(angular.y, angular.x);
00210                 shift_angle = 0.0;
00211                 // we'll always rotate around the centre of the panorama.
00212                 start_coordinates.x = 0.0;    start_coordinates.y = 0.0;
00213                 shift_coordinates.x = 0.0;    shift_coordinates.y = 0.0;
00214                 helper->SetStatusMessage(_("Rotate around the centre to roll."));
00215             }
00216             if (drag_yaw || drag_pitch)
00217             {
00218                 // We want to keep the point under the mouse pointer now under there
00219                 // wherever it goes. We'll calculate the roll, pitch, and yaw
00220                 // required to bring the centre to the point under the mouse. Then
00221                 // we rotate the panorama's images using the yaw and pitch of the
00222                 // movement. (Rotate start point to the centre, rotate by difference
00223                 // in yaw and pitch gained so far while dragging, then do the
00224                 // inverse of the rotation from start point to the centre on the
00225                 // result.
00226                 // set angles
00227                 double yaw, pitch;
00228                 hugin_utils::FDiff2D mouse_pos = helper->GetMousePanoPosition();
00229                 helper->GetVisualizationStatePtr()->GetProjectionInfo()->ImageToAngular(yaw,
00230                                                    pitch, mouse_pos.x, mouse_pos.y);
00231                 start_coordinates.x = yaw;    start_coordinates.y = pitch;
00232                 shift_coordinates.x = yaw;    shift_coordinates.y = pitch;
00233                 // provide a helpfull message to the user via the staus bar.
00234                 if (shift) {
00235                     helper->SetStatusMessage(_("Constrained drag: make a movement and it will be snapped to the yaw or pitch."));
00236                 } else {
00237                     helper->SetStatusMessage(_("Drag to move."));
00238                 }
00239             }
00240             if (drag_roll || drag_yaw || drag_pitch)
00241             {
00242                 shift_angle = 0.0;
00243                 // record where the images are so we know what the difference is.
00244                 // Use the component the mouse points to instead of every image.
00245                 // Find the components
00246 
00247                 /*
00248                     TODO: depending on state from the preview frame is not nice. 
00249                     but this cannot be avoided in this case as the drag tool must depend on a central state, 
00250                     which in this case is neither provided by the possibility of a central (parent) DragTool 
00251                     nor a parent ToolHelper. 
00252                     This is also the case for the identify tools, which inorder to interact with eachother
00253                     must rely on a central tool.
00254                     So the code at some point need to be refactored to provide central tool helper 
00255                     and central tools, similarly as the ViewState is now central 
00256                     compared to the VisualizationState which is specific to each visualization.
00257                 */
00258                 bool customDragging = helper->GetPreviewFrame()->individualDragging();
00259                 if (customDragging) {
00260                     draging_images = helper->GetPreviewFrame()->GetDragGroupImages();
00261                     std::set<unsigned int>::iterator i, end;
00262                     end = draging_images.end();
00263                     for (i = draging_images.begin(); i != end; ++i)
00264                     {
00265                         image_params[*i].Set(
00266                                 helper->GetViewStatePtr()->GetSrcImage(*i));
00267                     }
00268                     
00269                 } else {
00270 
00271 
00272                     HuginGraph::ImageGraph graph(*helper->GetPanoramaPtr());
00273                     HuginGraph::ImageGraph::Components components=graph.GetComponents();
00274                     const size_t n = components.size();
00275                     // If there is only component, we can drag everything. Otherwise the
00276                     // component we want is the lowest numbered image under the mouse.
00277                     if (n == 1)
00278                     {
00279                         unsigned int imgs = helper->GetPanoramaPtr()->getNrOfImages();
00280                         draging_images.clear();
00281                         fill_set(draging_images, 0, imgs - 1);
00282 
00283                         ViewState *view_state_ptr = helper->GetViewStatePtr();
00284                         for (unsigned int i = 0; i < imgs; i++)
00285                         {
00286                             image_params[i].Set(view_state_ptr->GetSrcImage(i));
00287                         };
00288                     } else
00289                     {
00290                         // multiple components or none at all.
00291                         if (n == 0 || helper->GetImageNumbersUnderMouse().empty())
00292                         {
00293                             // we can't drag nothing.
00294                             drag_roll = false; drag_yaw = false; drag_pitch = false;
00295                             return;
00296                         }
00297                         
00298                         // Find the component containing the topmost image under mouse
00299                         unsigned int img = *helper->GetImageNumbersUnderMouse().begin();
00300                         for (size_t component_index = 0;
00301                              component_index < n; component_index ++)
00302                         {
00303                             if (components[component_index].count(img))
00304                             {
00305                                 // Found it, record which images and where they are.
00306                                 draging_images = components[component_index];
00307                                 std::set<unsigned int>::iterator i, end;
00308                                 end = draging_images.end();
00309                                 for (i = draging_images.begin(); i != end; ++i)
00310                                 {
00311                                     image_params[*i].Set(
00312                                             helper->GetViewStatePtr()->GetSrcImage(*i));
00313                                 }
00314                                 break;
00315                             }
00316                         }
00317                     }
00318                 }
00319                 SetRotationMatrix(shift_coordinates.x, shift_coordinates.y,
00320                                   shift_angle,
00321                                   start_coordinates.x,  start_coordinates.y,  0.0);
00322             }
00323         }
00324     } else {
00325         // check this wasn't an attempt to drag empty space.
00326         if (! (drag_pitch || drag_roll || drag_yaw)) return;
00327         
00328         // Finished draging images:
00329         drag_yaw = false; drag_pitch = false; drag_roll = false;
00330         // Apply the rotations permanently.
00331         // find where the images end up.
00332         std::vector<HuginBase::SrcPanoImage> src_images(draging_images.size() + 1);
00333         std::map<unsigned int, ParamStore>::iterator i;
00334         unsigned int count = 0;
00335         for (i = image_params.begin(); i != image_params.end(); ++i)
00336         {
00337             double nyaw, npitch, nroll, nx, ny, nz, npy, npp;
00338             i->second.Move(&rotation_matrix, nyaw, npitch, nroll, nx, ny, nz, npy, npp);
00339             src_images[count] = helper->GetPanoramaPtr()->getSrcImage(i->first);
00340                         src_images[count].setX(nx);
00341                         src_images[count].setY(ny);
00342             src_images[count].setZ(nz);
00343             src_images[count].setTranslationPlaneYaw(npy);
00344             src_images[count].setTranslationPlanePitch(npp);
00345                 src_images[count].setYaw(nyaw);
00346                 src_images[count].setPitch(npitch);
00347                 src_images[count].setRoll(nroll);
00348                 count++;
00349         }
00350         PanoCommand::GlobalCmdHist::getInstance().addCommand(
00351             new PanoCommand::UpdateSrcImagesCmd(*helper->GetPanoramaPtr(),
00352                                             draging_images,
00353                                             src_images)
00354             );
00355         // stop dragging
00356         image_params.clear();
00357         
00358         helper->SetStatusMessage(_("Drag to move images (optionally use shift to constrain), or roll with right-drag or ctrl-drag."));
00359     }
00360 }
00361 
00362 
00363 
00364 void DragTool::ParamStore::Set(HuginBase::SrcPanoImage *img)
00365 {
00366     yaw = img->getYaw();
00367     pitch = img->getPitch();
00368     roll = img->getRoll();
00369     TrX = img->getX();
00370     TrY = img->getY();
00371     TrZ = img->getZ();
00372     Tpy = img->getTranslationPlaneYaw();
00373     Tpp = img->getTranslationPlanePitch();
00374 }
00375 
00376 void DragTool::ParamStore::Move(Matrix3 *matrix,
00377                                        double &yaw_out, double &pitch_out, double &roll_out, 
00378                                        double &TrX_out, double &TrY_out, double &TrZ_out,
00379                                        double &Tpy_out, double &Tpp_out)
00380 {
00381     Matrix3 start, output_matrix;
00382     // convert the location of this image to a matrix.
00383     start.SetRotationPT(DEG_TO_RAD(yaw), DEG_TO_RAD(pitch), DEG_TO_RAD(roll));
00384     // move it by the matrix specified.
00385     output_matrix = *matrix * start;
00386     // get the angles from the matrix
00387     output_matrix.GetRotationPT(yaw_out, pitch_out, roll_out);
00388     yaw_out = RAD_TO_DEG(yaw_out);
00389     pitch_out = RAD_TO_DEG(pitch_out);
00390     roll_out = RAD_TO_DEG(roll_out);
00391     
00392     if(TrX != 0.0 || TrY != 0.0 || TrZ != 0.0)
00393     {
00394         // rotate translation vector
00395         Vector3 vecRot=matrix->Inverse().TransformVector(Vector3(TrZ, TrX, TrY));
00396         TrX_out=vecRot.y;
00397         TrY_out=vecRot.z;
00398         TrZ_out=vecRot.x;
00399         // rotate translation plane
00400         start.SetRotationPT(DEG_TO_RAD(Tpy), DEG_TO_RAD(Tpp), 0.0);
00401         output_matrix = (*matrix) * start;
00402         double dummy;
00403         output_matrix.GetRotationPT(Tpy_out, Tpp_out, dummy);
00404         Tpy_out=RAD_TO_DEG(Tpy_out);
00405         Tpp_out=RAD_TO_DEG(Tpp_out);
00406     }
00407     else
00408     {
00409         TrX_out=0;
00410         TrY_out=0;
00411         TrZ_out=0;
00412         Tpy_out=0;
00413         Tpp_out=0;
00414     };
00415 }
00416 
00417 void DragTool::SetRotationMatrix(double yaw_shift, double pitch_shift,
00418                                         double roll_shift,
00419                                         double yaw_start, double pitch_start,
00420                                         double roll_start)
00421 {
00422     Matrix3 y1_mat, r_mat, y2_mat, p1_mat, p2_mat;
00423     // rotates the start point to the centre
00424     y1_mat.SetRotationPT(-DEG_TO_RAD(yaw_start), 0.0, 0.0);
00425     p1_mat.SetRotationPT(0.0, DEG_TO_RAD(pitch_start), 0.0);
00426     // rolls the image
00427     r_mat.SetRotationPT(0.0, 0.0, roll_shift);
00428     // rotates the centre to the destination point
00429     p2_mat.SetRotationPT(0.0, -DEG_TO_RAD(pitch_shift), 0.0);
00430     y2_mat.SetRotationPT(DEG_TO_RAD(yaw_shift), 0.0, 0.0);
00431     
00432     rotation_matrix = y2_mat * p2_mat * r_mat *p1_mat * y1_mat;
00433 }
00434 
00435 void PreviewDragTool::ReallyAfterDrawImagesEvent()
00436 {
00437     // draw guide lines down the middle.
00438     HuginBase::PanoramaOptions *opts = helper->GetViewStatePtr()->GetOptions();
00439     double width = (double) opts->getSize().width(),
00440            height = (double) opts->getSize().height();
00441     // Invert the color underneath.
00442     helper->GetViewStatePtr()->GetTextureManager()->DisableTexture();
00443     glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
00444     glEnable(GL_BLEND);
00445     glColor3f(1.0, 1.0, 1.0);
00446     glPushMatrix();
00447     glTranslatef(-0.5, -0.5, -0.5);    
00448     glBegin(GL_LINES);
00449         glVertex2f(width / 2.0, 0.0);
00450         glVertex2f(width / 2.0, height);
00451         glVertex2f(0.0,         height / 2.0);
00452         glVertex2f(width,       height / 2.0);        
00453     glEnd();
00454     // draw lines if we are dragging
00455     if (drag_roll)
00456     {
00457         // when rolling, a line from the centre (where we rotate around) in the
00458         // direction of the mouse pointer should help the user.
00459         double distance = width * width + height * height,
00460                angle = start_angle;
00461         glPushMatrix();
00462         glTranslatef(centre.x, centre.y, 0.0);
00463         glBegin(GL_LINES);
00464             // starting angle
00465             glVertex2d(0.0, 0.0);
00466             glVertex2f(distance * cos(angle), distance * sin(angle));
00467             // angle now used
00468             angle +=  shift_angle;
00469             glVertex2d(0.0, 0.0);
00470             glVertex2f(distance * cos(angle), distance * sin(angle));
00471         glEnd();
00472         glPopMatrix(); 
00473     }
00474     if (drag_pitch || drag_yaw)
00475     {
00476         // Draw a straight line in the spherical space, from the start point to
00477         // under the mouse. It only appears straight when using a cylinderical
00478         // projection or similar though, so we draw it as many line segments.
00479         glBegin(GL_LINE_STRIP);
00480             for (double t = 0.0; t <= 1.0; t+= 0.005)
00481             {
00482                 double x, y, ti = 1.0 - t;
00483                 helper->GetViewStatePtr()->GetProjectionInfo()->AngularToImage(
00484                              x, y,
00485                              t * start_coordinates.x + ti *shift_coordinates.x,
00486                              t * start_coordinates.y + ti *shift_coordinates.y);
00487                 glVertex2d(x, y);
00488             }
00489         glEnd();        
00490     }    
00491     glPopMatrix();
00492     glDisable(GL_BLEND);
00493     glEnable(GL_TEXTURE_2D);
00494 }
00495 
00496 void OverviewDragTool::ReallyAfterDrawImagesEvent()
00497 {
00498 
00499 }
00500 

Generated on 30 May 2016 for Hugintrunk by  doxygen 1.4.7