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 "CommandHistory.h"
00029 #include "PT/PanoCommand.h"
00030 #include "PT/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)
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 (abs(shift_coordinates.x - start_coordinates.x)
00103                     < 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                     PT::CPGraph graph;
00273                     PT::createCPGraph(*helper->GetPanoramaPtr(), graph);
00274                     PT::CPComponents components;
00275                     unsigned int n = PT::findCPComponents(graph, components);
00276                     // If there is only component, we can drag everything. Otherwise the
00277                     // component we want is the lowest numbered image under the mouse.
00278                     if (n == 1)
00279                     {
00280                         unsigned int imgs = helper->GetPanoramaPtr()->getNrOfImages();
00281                         draging_images.clear();
00282                         fill_set(draging_images, 0, imgs - 1);
00283 
00284                         ViewState *view_state_ptr = helper->GetViewStatePtr();
00285                         for (unsigned int i = 0; i < imgs; i++)
00286                         {
00287                             image_params[i].Set(view_state_ptr->GetSrcImage(i));
00288                         };
00289                     } else
00290                     {
00291                         // multiple components or none at all.
00292                         if (n == 0 || helper->GetImageNumbersUnderMouse().empty())
00293                         {
00294                             // we can't drag nothing.
00295                             drag_roll = false; drag_yaw = false; drag_pitch = false;
00296                             return;
00297                         }
00298                         
00299                         // Find the component containing the topmost image under mouse
00300                         unsigned int img = *helper->GetImageNumbersUnderMouse().begin();
00301                         for (unsigned int component_index = 0;
00302                              component_index < components.size(); component_index ++)
00303                         {
00304                             if (components[component_index].count(img))
00305                             {
00306                                 // Found it, record which images and where they are.
00307                                 draging_images = components[component_index];
00308                                 std::set<unsigned int>::iterator i, end;
00309                                 end = draging_images.end();
00310                                 for (i = draging_images.begin(); i != end; i++)
00311                                 {
00312                                     image_params[*i].Set(
00313                                             helper->GetViewStatePtr()->GetSrcImage(*i));
00314                                 }
00315                                 break;
00316                             }
00317                         }
00318                     }
00319                 }
00320                 SetRotationMatrix(shift_coordinates.x, shift_coordinates.y,
00321                                   shift_angle,
00322                                   start_coordinates.x,  start_coordinates.y,  0.0);
00323             }
00324         }
00325     } else {
00326         // check this wasn't an attempt to drag empty space.
00327         if (! (drag_pitch || drag_roll || drag_yaw)) return;
00328         
00329         // Finished draging images:
00330         drag_yaw = false; drag_pitch = false; drag_roll = false;
00331         // Apply the rotations permanently.
00332         // find where the images end up.
00333         std::vector<HuginBase::SrcPanoImage> src_images(draging_images.size() + 1);
00334         std::map<unsigned int, ParamStore>::iterator i;
00335         unsigned int count = 0;
00336         for (i = image_params.begin(); i != image_params.end(); i++)
00337         {
00338             double nyaw, npitch, nroll, nx, ny, nz, npy, npp;
00339             i->second.Move(&rotation_matrix, nyaw, npitch, nroll, nx, ny, nz, npy, npp);
00340             src_images[count] = helper->GetPanoramaPtr()->getSrcImage(i->first);
00341                         src_images[count].setX(nx);
00342                         src_images[count].setY(ny);
00343             src_images[count].setZ(nz);
00344             src_images[count].setTranslationPlaneYaw(npy);
00345             src_images[count].setTranslationPlanePitch(npp);
00346                 src_images[count].setYaw(nyaw);
00347                 src_images[count].setPitch(npitch);
00348                 src_images[count].setRoll(nroll);
00349                 count++;
00350         }
00351         GlobalCmdHist::getInstance().addCommand(
00352             new PT::UpdateSrcImagesCmd(*helper->GetPanoramaPtr(),
00353                                             draging_images,
00354                                             src_images)
00355             );
00356         // stop dragging
00357         image_params.clear();
00358         
00359         helper->SetStatusMessage(_("Drag to move images (optionally use shift to constrain), or roll with right-drag or ctrl-drag."));
00360     }
00361 }
00362 
00363 
00364 
00365 void DragTool::ParamStore::Set(HuginBase::SrcPanoImage *img)
00366 {
00367     yaw = img->getYaw();
00368     pitch = img->getPitch();
00369     roll = img->getRoll();
00370     TrX = img->getX();
00371     TrY = img->getY();
00372     TrZ = img->getZ();
00373     Tpy = img->getTranslationPlaneYaw();
00374     Tpp = img->getTranslationPlanePitch();
00375 }
00376 
00377 void DragTool::ParamStore::Move(Matrix3 *matrix,
00378                                        double &yaw_out, double &pitch_out, double &roll_out, 
00379                                        double &TrX_out, double &TrY_out, double &TrZ_out,
00380                                        double &Tpy_out, double &Tpp_out)
00381 {
00382     Matrix3 start, output_matrix;
00383     // convert the location of this image to a matrix.
00384     start.SetRotationPT(DEG_TO_RAD(yaw), DEG_TO_RAD(pitch), DEG_TO_RAD(roll));
00385     // move it by the matrix specified.
00386     output_matrix = *matrix * start;
00387     // get the angles from the matrix
00388     output_matrix.GetRotationPT(yaw_out, pitch_out, roll_out);
00389     yaw_out = RAD_TO_DEG(yaw_out);
00390     pitch_out = RAD_TO_DEG(pitch_out);
00391     roll_out = RAD_TO_DEG(roll_out);
00392     
00393     if(TrX != 0.0 || TrY != 0.0 || TrZ != 0.0)
00394     {
00395         // rotate translation vector
00396         Vector3 vecRot=matrix->Inverse().TransformVector(Vector3(TrZ, TrX, TrY));
00397         TrX_out=vecRot.y;
00398         TrY_out=vecRot.z;
00399         TrZ_out=vecRot.x;
00400         // rotate translation plane
00401         start.SetRotationPT(DEG_TO_RAD(Tpy), DEG_TO_RAD(Tpp), 0.0);
00402         output_matrix = (*matrix) * start;
00403         double dummy;
00404         output_matrix.GetRotationPT(Tpy_out, Tpp_out, dummy);
00405         Tpy_out=RAD_TO_DEG(Tpy_out);
00406         Tpp_out=RAD_TO_DEG(Tpp_out);
00407     }
00408     else
00409     {
00410         TrX_out=0;
00411         TrY_out=0;
00412         TrZ_out=0;
00413         Tpy_out=0;
00414         Tpp_out=0;
00415     };
00416 }
00417 
00418 void DragTool::SetRotationMatrix(double yaw_shift, double pitch_shift,
00419                                         double roll_shift,
00420                                         double yaw_start, double pitch_start,
00421                                         double roll_start)
00422 {
00423     Matrix3 y1_mat, r_mat, y2_mat, p1_mat, p2_mat;
00424     // rotates the start point to the centre
00425     y1_mat.SetRotationPT(-DEG_TO_RAD(yaw_start), 0.0, 0.0);
00426     p1_mat.SetRotationPT(0.0, DEG_TO_RAD(pitch_start), 0.0);
00427     // rolls the image
00428     r_mat.SetRotationPT(0.0, 0.0, roll_shift);
00429     // rotates the centre to the destination point
00430     p2_mat.SetRotationPT(0.0, -DEG_TO_RAD(pitch_shift), 0.0);
00431     y2_mat.SetRotationPT(DEG_TO_RAD(yaw_shift), 0.0, 0.0);
00432     
00433     rotation_matrix = y2_mat * p2_mat * r_mat *p1_mat * y1_mat;
00434 }
00435 
00436 void PreviewDragTool::ReallyAfterDrawImagesEvent()
00437 {
00438     // draw guide lines down the middle.
00439     HuginBase::PanoramaOptions *opts = helper->GetViewStatePtr()->GetOptions();
00440     double width = (double) opts->getSize().width(),
00441            height = (double) opts->getSize().height();
00442     // Invert the color underneath.
00443     helper->GetViewStatePtr()->GetTextureManager()->DisableTexture();
00444     glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
00445     glEnable(GL_BLEND);
00446     glColor3f(1.0, 1.0, 1.0);
00447     glPushMatrix();
00448     glTranslatef(-0.5, -0.5, -0.5);    
00449     glBegin(GL_LINES);
00450         glVertex2f(width / 2.0, 0.0);
00451         glVertex2f(width / 2.0, height);
00452         glVertex2f(0.0,         height / 2.0);
00453         glVertex2f(width,       height / 2.0);        
00454     glEnd();
00455     // draw lines if we are dragging
00456     if (drag_roll)
00457     {
00458         // when rolling, a line from the centre (where we rotate around) in the
00459         // direction of the mouse pointer should help the user.
00460         double distance = width * width + height * height,
00461                angle = start_angle;
00462         glPushMatrix();
00463         glTranslatef(centre.x, centre.y, 0.0);
00464         glBegin(GL_LINES);
00465             // starting angle
00466             glVertex2d(0.0, 0.0);
00467             glVertex2f(distance * cos(angle), distance * sin(angle));
00468             // angle now used
00469             angle +=  shift_angle;
00470             glVertex2d(0.0, 0.0);
00471             glVertex2f(distance * cos(angle), distance * sin(angle));
00472         glEnd();
00473         glPopMatrix(); 
00474     }
00475     if (drag_pitch || drag_yaw)
00476     {
00477         // Draw a straight line in the spherical space, from the start point to
00478         // under the mouse. It only appears straight when using a cylinderical
00479         // projection or similar though, so we draw it as many line segments.
00480         glBegin(GL_LINE_STRIP);
00481             for (double t = 0.0; t <= 1.0; t+= 0.005)
00482             {
00483                 double x, y, ti = 1.0 - t;
00484                 helper->GetViewStatePtr()->GetProjectionInfo()->AngularToImage(
00485                              x, y,
00486                              t * start_coordinates.x + ti *shift_coordinates.x,
00487                              t * start_coordinates.y + ti *shift_coordinates.y);
00488                 glVertex2d(x, y);
00489             }
00490         glEnd();        
00491     }    
00492     glPopMatrix();
00493     glDisable(GL_BLEND);
00494     glEnable(GL_TEXTURE_2D);
00495 }
00496 
00497 void OverviewDragTool::ReallyAfterDrawImagesEvent()
00498 {
00499 
00500 }
00501 

Generated on Wed Oct 1 01:25:33 2014 for Hugintrunk by  doxygen 1.3.9.1