PreviewPanel.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00027 #include <config.h>
00028 
00029 #include "panoinc_WX.h"
00030 #include "panoinc.h"
00031 
00032 #include <vigra/basicimageview.hxx>
00033 #include "nona/Stitcher.h"
00034 
00035 #include "base_wx/wxImageCache.h"
00036 #include "hugin/PreviewPanel.h"
00037 #include "hugin/PreviewFrame.h"
00038 #include "hugin/MainFrame.h"
00039 #include "base_wx/CommandHistory.h"
00040 #include "base_wx/PanoCommand.h"
00041 #include "base_wx/wxcms.h"
00042 #include "hugin/config_defaults.h"
00043 #include "hugin/huginApp.h"
00044 
00045 #include <math.h>
00046 
00047 using namespace std;
00048 using namespace vigra;
00049 using namespace vigra_ext;
00050 using namespace hugin_utils;
00051 
00052 typedef RGBValue<unsigned char> BRGBValue;
00053 
00054 BEGIN_EVENT_TABLE(PreviewPanel, wxPanel)
00055     EVT_SIZE(PreviewPanel::OnResize)
00056     EVT_LEFT_DOWN(PreviewPanel::mousePressLMBEvent)
00057     EVT_RIGHT_DOWN(PreviewPanel::mousePressRMBEvent)
00058     EVT_MOUSE_EVENTS ( PreviewPanel::OnMouse )
00059     EVT_PAINT ( PreviewPanel::OnDraw )
00060 END_EVENT_TABLE()
00061 
00062 PreviewPanel::PreviewPanel()
00063     : pano(0), m_autoPreview(false),m_panoImgSize(1,1),
00064     m_panoBitmap(0), 
00065     m_pano2erect(0), m_blendMode(BLEND_COPY), 
00066     m_state_rendering(false), m_rerender(false), m_imgsDirty(true)
00067 {
00068 }
00069 
00070 bool PreviewPanel::Create(wxWindow* parent, wxWindowID id,
00071                            const wxPoint& pos,
00072                            const wxSize& size,
00073                            long style,
00074                            const wxString& name)
00075 {
00076     DEBUG_TRACE(" Create called *************");
00077     if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
00078         return false;
00079     }
00080     DEBUG_TRACE("");
00081     DEBUG_DEBUG("m_state_rendering = " << m_state_rendering);
00082 
00083 #if defined(__WXMSW__) 
00084     wxString cursorPath = huginApp::Get()->GetXRCPath() + wxT("/data/cursor_cp_pick.cur");
00085     m_cursor = new wxCursor(cursorPath, wxBITMAP_TYPE_CUR);
00086 #else
00087     m_cursor = new wxCursor(wxCURSOR_CROSS);
00088 #endif
00089     SetCursor(*m_cursor);
00090     return true;
00091 }
00092 
00093 
00094 void PreviewPanel::Init(PreviewFrame *parent, HuginBase::Panorama * panorama )
00095 {
00096     pano = panorama;
00097     parentWindow = parent;
00098     pano->addObserver(this);
00099 }
00100 
00101 
00102 PreviewPanel::~PreviewPanel()
00103 {
00104     DEBUG_TRACE("dtor");
00105     delete m_cursor;
00106     pano->removeObserver(this);
00107     if (m_panoBitmap) {
00108         delete m_panoBitmap;
00109     }
00110     if (m_pano2erect) {
00111         delete m_pano2erect;
00112     }
00113     DEBUG_TRACE("dtor end");
00114 }
00115 
00116 void PreviewPanel::panoramaChanged(HuginBase::Panorama &pano)
00117 {
00118     // avoid recursive calls.. don't know if they can happen at all,
00119     // but they might lead to crashes.
00120     bool dirty = false;
00121 
00122     const HuginBase::PanoramaOptions & newOpts = pano.getOptions();
00123 
00124     // check if an important options has been changed
00125     if (newOpts.getHFOV() != opts.getHFOV()) {
00126         DEBUG_DEBUG("HFOV changed");
00127         dirty = true;
00128     }
00129     if (newOpts.getVFOV() != opts.getVFOV()) {
00130         DEBUG_DEBUG("VFOV changed");
00131         dirty = true;
00132     }
00133     if (newOpts.getProjection() != opts.getProjection()) {
00134         DEBUG_DEBUG("projection changed");
00135         dirty = true;
00136     }
00137 
00138     if (newOpts.getProjectionParameters() != opts.getProjectionParameters() ) {
00139         DEBUG_DEBUG("projection parameters changed");
00140         dirty = true;
00141     }
00142     if (newOpts.outputExposureValue != opts.outputExposureValue )
00143     {
00144         DEBUG_DEBUG("output exposure value changed");
00145         dirty = true;
00146     };
00147 
00148     opts = newOpts;
00149     if (dirty) {
00150         // have to remap all images
00151         m_remapCache.invalidate();
00152     }
00153 
00154     if (m_autoPreview && dirty) {
00155         DEBUG_DEBUG("forcing preview update");
00156         ForceUpdate();
00157         // resize
00158     } else if(m_autoPreview && m_imgsDirty ) {
00159         DEBUG_DEBUG("updating preview after image change");
00160         updatePreview();
00161         m_imgsDirty=false;
00162     }
00163 }
00164 
00165 void PreviewPanel::panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &changed)
00166 {
00167     DEBUG_TRACE("");
00168     m_imgsDirty = true;
00169 }
00170 
00171 void PreviewPanel::SetBlendMode(BlendMode b)
00172 {
00173     m_blendMode = b;
00174     updatePreview();
00175 }
00176 
00177 void PreviewPanel::ForceUpdate()
00178 {
00179     updatePreview();
00180 }
00181 
00182 void PreviewPanel::SetAutoUpdate(bool enabled)
00183 {
00184     m_autoPreview = enabled;
00185     if (enabled) {
00186         updatePreview();
00187     }
00188 }
00189 
00192 template <class OP>
00193 struct ExposureResponseFunctor2
00194 {
00195     ExposureResponseFunctor2(double exposure, const OP & operation)
00196     : op(operation), e(exposure)
00197     {
00198     }
00199     const OP & op;
00200     double e;
00201 
00202     template <class VT>
00203     typename vigra::NumericTraits<VT>::RealPromote
00204     operator()(VT v) const 
00205     {
00206         return op(v*e);
00207     }
00208 };
00209 
00210 
00211 void PreviewPanel::updatePreview()
00212 {
00213     DEBUG_TRACE("");
00214 
00215     // we can accidentally end up here recursively, because wxWidgets
00216     // allows user input during redraw of the progress in the bottom
00217     if (m_state_rendering) {
00218         DEBUG_DEBUG("m_state_rendering == true, aborting rendering");
00219         m_rerender = true;
00220         return;
00221     }
00222 
00223     DEBUG_DEBUG("m_state_rendering = true");
00224     m_state_rendering = true;
00225     m_rerender = false;
00226 
00227         {
00228           // Even though the frame is hidden, the panel is not
00229           // so check the parent instead
00230           if (parentWindow) {
00231                 if (parentWindow->IsShown() && (! parentWindow->IsIconized())) {
00232                   DEBUG_INFO("Parent window shown - updating");
00233                 } else {
00234                   DEBUG_INFO("Parent window hidden - not updating");
00235                   m_state_rendering = false;
00236                   return;
00237                 }
00238           }
00239         }
00240     wxBusyCursor wait;
00241     double finalWidth = pano->getOptions().getWidth();
00242     double finalHeight = pano->getOptions().getHeight();
00243 
00244     m_panoImgSize = Diff2D(GetClientSize().GetWidth(), GetClientSize().GetHeight());
00245 
00246     double ratioPano = finalWidth / finalHeight;
00247     double ratioPanel = (double)m_panoImgSize.x / (double)m_panoImgSize.y;
00248 
00249     DEBUG_DEBUG("panorama ratio: " << ratioPano << "  panel ratio: " << ratioPanel);
00250 
00251     if (ratioPano < ratioPanel) {
00252         // panel is wider than pano
00253         m_panoImgSize.x = hugin_utils::round(m_panoImgSize.y * ratioPano);
00254         DEBUG_DEBUG("portrait: " << m_panoImgSize);
00255     } else {
00256         // panel is taller than pano
00257         m_panoImgSize.y = hugin_utils::round(m_panoImgSize.x / ratioPano);
00258         DEBUG_DEBUG("landscape: " << m_panoImgSize);
00259     }
00260 
00261     HuginBase::PanoramaOptions opts = pano->getOptions();
00262     //don't use GPU for preview
00263     opts.remapUsingGPU = false;
00264     opts.setWidth(m_panoImgSize.x, false);
00265     opts.setHeight(m_panoImgSize.y);
00266     // always use bilinear for preview.
00267 
00268     // reset ROI. The preview needs to draw the parts outside the ROI, too!
00269     opts.setROI(Rect2D(opts.getSize()));
00270     opts.interpolator = vigra_ext::INTERP_BILINEAR;
00271 
00272     // create images
00273     wxImage panoImage(m_panoImgSize.x, m_panoImgSize.y);
00274     try {
00275         vigra::BasicImageView<RGBValue<unsigned char> > panoImg8((RGBValue<unsigned char> *)panoImage.GetData(), panoImage.GetWidth(), panoImage.GetHeight());
00276         FRGBImage panoImg(m_panoImgSize);
00277         BImage alpha(m_panoImgSize);
00278 
00279         DEBUG_DEBUG("about to stitch images, pano size: " << m_panoImgSize);
00280         HuginBase::UIntSet displayedImages = pano->getActiveImages();
00281         if (displayedImages.size() > 0) {
00282             if (opts.outputMode == HuginBase::PanoramaOptions::OUTPUT_HDR) {
00283                 DEBUG_DEBUG("HDR output merge");
00284 
00285                 ReduceToHDRFunctor<RGBValue<float> > hdrmerge;
00286                 HuginBase::Nona::ReduceStitcher<FRGBImage, BImage> stitcher(*pano, parentWindow);
00287                 stitcher.stitch(opts, displayedImages,
00288                                 destImageRange(panoImg), destImage(alpha),
00289                                 m_remapCache,
00290                                 hdrmerge);
00291 #ifdef DEBUG_REMAP
00292 {
00293     vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin04_preview_HDR_Reduce.tif"); \
00294             vigra::exportImage(vigra::srcImageRange(panoImg), exi); \
00295 }
00296 {
00297     vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_preview_HDR_Reduce_Alpha.tif"); \
00298             vigra::exportImage(vigra::srcImageRange(alpha), exi); \
00299 }
00300 #endif
00301 
00302                 // find min and max
00303                 vigra::FindMinMax<float> minmax;   // init functor
00304                 vigra::inspectImageIf(srcImageRange(panoImg), srcImage(alpha),
00305                                     minmax);
00306                 double min = std::max(minmax.min, 1e-6f);
00307                 double max = minmax.max;
00308 
00309                 int mapping = wxConfigBase::Get()->Read(wxT("/ImageCache/MappingFloat"), HUGIN_IMGCACHE_MAPPING_FLOAT);
00310                 applyMapping(srcImageRange(panoImg), destImage(panoImg8), min, max, mapping);
00311 
00312             } else {
00313                     // LDR output
00314                 vigra::ImageImportInfo::ICCProfile iccProfile;
00315                 switch (m_blendMode) {
00316                 case BLEND_COPY:
00317                 {
00318                     HuginBase::Nona::StackingBlender blender;
00319                     HuginBase::Nona::SimpleStitcher<FRGBImage, BImage> stitcher(*pano, parentWindow);
00320                     stitcher.stitch(opts, displayedImages,
00321                                     destImageRange(panoImg), destImage(alpha),
00322                                     m_remapCache,
00323                                     blender);
00324                     iccProfile = stitcher.iccProfile;
00325                     break;
00326                 }
00327                 case BLEND_DIFFERENCE:
00328                 {
00329                     HuginBase::Nona::ReduceToDifferenceFunctor<RGBValue<float> > func;
00330                     HuginBase::Nona::ReduceStitcher<FRGBImage, BImage> stitcher(*pano, parentWindow);
00331                     stitcher.stitch(opts, displayedImages,
00332                                     destImageRange(panoImg), destImage(alpha),
00333                                     m_remapCache,
00334                                     func);
00335                     iccProfile = stitcher.iccProfile;
00336                     break;
00337                 }
00338                 }
00339                 
00340 #ifdef DEBUG_REMAP
00341 {
00342     vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin04_preview_AfterRemap.tif"); \
00343             vigra::exportImage(vigra::srcImageRange(panoImg), exi); \
00344 }
00345 {
00346     vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_preview_AfterRemapAlpha.tif"); \
00347             vigra::exportImage(vigra::srcImageRange(alpha), exi); \
00348 }
00349 #endif
00350 
00351                 // apply default exposure and convert to 8 bit
00352                 HuginBase::SrcPanoImage src = pano->getSrcImage(0);
00353 
00354                 // apply the exposure
00355                 double scale = 1.0/pow(2.0,opts.outputExposureValue);
00356 
00357                 vigra::transformImage(srcImageRange(panoImg), destImage(panoImg),
00358                                       vigra::functor::Arg1()*vigra::functor::Param(scale));
00359 
00360                 DEBUG_DEBUG("LDR output, with response: " << src.getResponseType());
00361                 if (src.getResponseType() == HuginBase::SrcPanoImage::RESPONSE_LINEAR) {
00362                     vigra::transformImage(srcImageRange(panoImg), destImage(panoImg8),
00363                                           vigra::functor::Arg1()*vigra::functor::Param(255));
00364                 } else {
00365                 // create suitable lut for response
00366                     typedef  std::vector<double> LUT;
00367                     LUT lut;
00368                     switch(src.getResponseType())
00369                     {
00370                         case HuginBase::SrcPanoImage::RESPONSE_EMOR:
00371                             EMoR::createEMoRLUT(src.getEMoRParams(), lut);
00372                             break;
00373                         case HuginBase::SrcPanoImage::RESPONSE_GAMMA:
00374                             lut.resize(256);
00375                             createGammaLUT(1/src.getGamma(), lut);
00376                             break;
00377                         default:
00378                             vigra_fail("Unknown or unsupported response function type");
00379                             break;
00380                     }
00381                     // scale lut
00382                     for (size_t i=0; i < lut.size(); i++) 
00383                         lut[i] = lut[i]*255;
00384                     typedef vigra::RGBValue<float> FRGB;
00385                     LUTFunctor<FRGB, LUT> lutf(lut);
00386 
00387                     vigra::transformImage(srcImageRange(panoImg), destImage(panoImg8),
00388                                           lutf);
00389                 }
00390                 // apply color profiles
00391                 if (!iccProfile.empty() || huginApp::Get()->HasMonitorProfile())
00392                 {
00393                     HuginBase::Color::CorrectImage(panoImage, iccProfile, huginApp::Get()->GetMonitorProfile());
00394                 };
00395             }
00396         }
00397 
00398 #ifdef DEBUG_REMAP
00399 {
00400     vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin05_preview_final.tif"); \
00401             vigra::exportImage(vigra::srcImageRange(panoImg8), exi); \
00402 }
00403 #endif
00404 
00405 
00406     } catch (std::exception & e) {
00407         m_state_rendering = false;
00408         DEBUG_ERROR("error during stitching: " << e.what());
00409         wxMessageBox(wxString(e.what(), wxConvLocal), _("Error during Stitching"));
00410     }
00411 
00412 
00413     // update the transform for pano -> erect coordinates
00414     if (m_pano2erect) delete m_pano2erect;
00415     HuginBase::SrcPanoImage src;
00416     src.setProjection(HuginBase::SrcPanoImage::EQUIRECTANGULAR);
00417     src.setHFOV(360);
00418     src.setSize(Size2D(360,180));
00419     m_pano2erect = new HuginBase::PTools::Transform;
00420     m_pano2erect->createTransform(src, opts);
00421 
00422     if (m_panoBitmap) {
00423         delete m_panoBitmap;
00424     }
00425     m_panoBitmap = new wxBitmap(panoImage);
00426 
00427 
00428     // always redraw
00429     wxClientDC dc(this);
00430     DrawPreview(dc);
00431 
00432     m_state_rendering = false;
00433     DEBUG_DEBUG("m_state_rendering = false");
00434     m_rerender = false;
00435 }
00436 
00437 
00438 void PreviewPanel::DrawPreview(wxDC & dc)
00439 {
00440     if (!IsShown()){
00441         return;
00442     }
00443     DEBUG_TRACE("");
00444 
00445     int offsetX = 0;
00446     int offsetY = 0;
00447 
00448     wxSize sz = GetClientSize();
00449     if (sz.GetWidth() > m_panoImgSize.x) {
00450         offsetX = (sz.GetWidth() - m_panoImgSize.x) / 2;
00451     }
00452     if (sz.GetHeight() > m_panoImgSize.y) {
00453         offsetY = (sz.GetHeight() - m_panoImgSize.y) / 2;
00454     }
00455 
00456 #if wxCHECK_VERSION(3,0,0)
00457     dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
00458     dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
00459 #else
00460     dc.SetPen(wxPen(GetBackgroundColour(), 1, wxSOLID));
00461     dc.SetBrush(wxBrush(GetBackgroundColour(),wxSOLID));
00462 #endif
00463     dc.DrawRectangle(0, 0, offsetX, sz.GetHeight());
00464     dc.DrawRectangle(offsetX, 0, sz.GetWidth(), offsetY);
00465     dc.DrawRectangle(offsetX, sz.GetHeight() - offsetY,
00466                      sz.GetWidth(), sz.GetHeight());
00467     dc.DrawRectangle(sz.GetWidth() - offsetX, offsetY,
00468                      sz.GetWidth(), sz.GetHeight() - offsetY);
00469 
00470     // set a clip region to draw stuff accordingly
00471     dc.DestroyClippingRegion();
00472     dc.SetClippingRegion(offsetX, offsetY,
00473                          m_panoImgSize.x, m_panoImgSize.y);
00474 
00475 #if wxCHECK_VERSION(3,0,0)
00476     dc.SetPen(wxPen(wxT("BLACK"), 1, wxPENSTYLE_SOLID));
00477     dc.SetBrush(wxBrush(wxT("BLACK"), wxBRUSHSTYLE_SOLID));
00478 #else
00479     dc.SetPen(wxPen(wxT("BLACK"), 1, wxSOLID));
00480     dc.SetBrush(wxBrush(wxT("BLACK"),wxSOLID));
00481 #endif
00482     dc.DrawRectangle(offsetX, offsetY, m_panoImgSize.x, m_panoImgSize.y);
00483 
00484 
00485     wxCoord w = m_panoImgSize.x;
00486     wxCoord h = m_panoImgSize.y;
00487 
00488 
00489     // draw panorama image
00490     if (m_panoBitmap) {
00491 
00492         dc.DrawBitmap(*m_panoBitmap, offsetX, offsetY);
00493 
00494         // draw ROI
00495         Size2D panoSize =  pano->getOptions().getSize();
00496         Rect2D panoROI =  pano->getOptions().getROI();
00497         if (panoROI != vigra::Rect2D(panoSize)) {
00498 
00499             double scale = min(w/(double)panoSize.x, h/(double)panoSize.y);
00500             Rect2D previewROI = Rect2D(panoROI.upperLeft()* scale, panoROI.lowerRight() * scale);
00501             Rect2D screenROI = previewROI;
00502             screenROI.moveBy(offsetX, offsetY);
00503 
00504 
00505             // TODO: make areas outside ROI darker than the rest of the image
00506             // overdraw areas outside the ROI with some black half transparent
00507             // bitmap
00508             // it seems to be quite complicated to create a half transparent black image...
00509             wxImage blackImg(w,h);
00510             // init alpha channel
00511             if (!blackImg.HasAlpha()) {
00512                 blackImg.InitAlpha();
00513             }
00514             unsigned char * aptr = blackImg.GetAlpha();
00515             unsigned char * aend = aptr + w*h;
00516             for (; aptr != aend; ++aptr)
00517                 *aptr = 128;
00518             wxBitmap blackBitmap(blackImg);
00519 
00520             // left
00521             if (screenROI.left() > offsetX) {
00522                 dc.DestroyClippingRegion();
00523                 dc.SetClippingRegion(offsetX, offsetY,
00524                                      previewROI.left(), h);
00525                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00526             }
00527             // top
00528             if (screenROI.top() > offsetY ) {
00529                 dc.DestroyClippingRegion();
00530                 dc.SetClippingRegion(screenROI.left(), offsetY,
00531                                      previewROI.width(), previewROI.top());
00532                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00533             }
00534             // right
00535             if (screenROI.right() < offsetX + w) {
00536                 dc.DestroyClippingRegion();
00537                 dc.SetClippingRegion(screenROI.right(), offsetY,
00538                                      w - previewROI.right(), h);
00539                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00540             }
00541             // bottom
00542             if (screenROI.bottom() < offsetY + h ) {
00543                 dc.DestroyClippingRegion();
00544                 dc.SetClippingRegion(screenROI.left(), screenROI.bottom(),
00545                                      screenROI.width(), h - previewROI.bottom());
00546                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00547             }
00548 
00549 
00550             // reset clipping region
00551             dc.DestroyClippingRegion();
00552             dc.SetClippingRegion(offsetX, offsetY,
00553                          m_panoImgSize.x, m_panoImgSize.y);
00554 
00555             // draw boundaries
00556 #if wxCHECK_VERSION(3,0,0)
00557             dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
00558 #else
00559             dc.SetPen(wxPen(wxT("WHITE"), 1, wxSOLID));
00560 #endif
00561             dc.SetLogicalFunction(wxINVERT);
00562 
00563             DEBUG_DEBUG("ROI scale factor: " << scale << " screen ROI: " << screenROI);
00564 
00565             dc.DrawLine(screenROI.left(),screenROI.top(),
00566                         screenROI.right(),screenROI.top());
00567             dc.DrawLine(screenROI.right(),screenROI.top(),
00568                         screenROI.right(),screenROI.bottom());
00569             dc.DrawLine(screenROI.right(),screenROI.bottom(),
00570                         screenROI.left(),screenROI.bottom());
00571             dc.DrawLine(screenROI.left(),screenROI.bottom(),
00572                         screenROI.left(),screenROI.top());
00573 
00574 
00575         }
00576     }
00577 
00578     dc.DestroyClippingRegion();
00579     dc.SetClippingRegion(offsetX, offsetY,
00580                     m_panoImgSize.x, m_panoImgSize.y);
00581 
00582     // draw center lines over display
00583 #if wxCHECK_VERSION(3,0,0)
00584     dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
00585 #else
00586     dc.SetPen(wxPen(wxT("WHITE"), 1, wxSOLID));
00587 #endif
00588     dc.SetLogicalFunction(wxINVERT);
00589     dc.DrawLine(offsetX + w/2, offsetY,
00590                 offsetX + w/2, offsetY + h);
00591     dc.DrawLine(offsetX, offsetY + h/2,
00592                 offsetX + w, offsetY+ h/2);
00593 
00594 }
00595 
00596 void PreviewPanel::OnDraw(wxPaintEvent & event)
00597 {
00598     wxPaintDC dc(this);
00599     DrawPreview(dc);
00600 }
00601 
00602 void PreviewPanel::OnResize(wxSizeEvent & e)
00603 {
00604     DEBUG_TRACE("");
00605     wxSize sz = GetClientSize();
00606     if (sz.GetWidth() != m_panoImgSize.x && sz.GetHeight() != m_panoImgSize.y) {
00607         m_remapCache.invalidate();
00608         if (m_autoPreview) {
00609             ForceUpdate();
00610         }
00611     }
00612 }
00613 
00614 
00615 void PreviewPanel::mousePressLMBEvent(wxMouseEvent & e)
00616 {
00617     DEBUG_DEBUG("mousePressLMBEvent: " << e.m_x << "x" << e.m_y);
00618     double yaw, pitch;
00619     mouse2erect(e.m_x, e.m_y,  yaw, pitch);
00620     // calculate new rotation angles.
00621     Matrix3 rotY;
00622     rotY.SetRotationPT(DEG_TO_RAD(-yaw), 0, 0);
00623     Matrix3 rotP;
00624     rotP.SetRotationPT(0, DEG_TO_RAD(pitch), 0);
00625 
00626     double y,p,r;
00627     Matrix3 rot = rotP * rotY;
00628     rot.GetRotationPT(y,p,r);
00629     y = RAD_TO_DEG(y);
00630     p = RAD_TO_DEG(p);
00631     r = RAD_TO_DEG(r);
00632     DEBUG_DEBUG("rotation angles pitch*yaw: " << y << " " << p << " " << r);
00633 
00634     PanoCommand::GlobalCmdHist::getInstance().addCommand(
00635             new PanoCommand::RotatePanoCmd(*pano, y, p, r)
00636         );
00637     if (!m_autoPreview) {
00638         ForceUpdate();
00639     }
00640 }
00641 
00642 
00643 void PreviewPanel::mousePressRMBEvent(wxMouseEvent & e)
00644 {
00645     DEBUG_DEBUG("mousePressRMBEvent: " << e.m_x << "x" << e.m_y);
00646     double yaw, pitch;
00647     mouse2erect(e.m_x, e.m_y,  yaw, pitch);
00648     // theta, phi: spherical coordinates in mathworld notation.
00649     double theta = DEG_TO_RAD(yaw);
00650     double phi = DEG_TO_RAD(90+pitch);
00651     // convert to cartesian coordinates.
00652     double x = cos(theta)* sin(phi);
00653     double y = sin(theta)* sin(phi);
00654     double z = cos(phi);
00655     DEBUG_DEBUG("theta: " << theta << " phi: " << phi << " x y z:" << x << " " << y << " " << z);
00656     double roll = RAD_TO_DEG(atan(z/y));
00657 
00658     DEBUG_DEBUG("roll correction: " << roll);
00659 
00660     PanoCommand::GlobalCmdHist::getInstance().addCommand(
00661             new PanoCommand::RotatePanoCmd(*pano, 0, 0, roll)
00662         );
00663     if (!m_autoPreview) {
00664         ForceUpdate();
00665     }
00666 }
00667 
00668 
00669 void PreviewPanel::OnMouse(wxMouseEvent & e)
00670 {
00671     double yaw, pitch;
00672     mouse2erect(e.m_x, e.m_y,  yaw, pitch);
00673 
00674     parentWindow->SetStatusText(_("Left click to define new center point, right click to move point to horizon."),0);
00675     parentWindow->SetStatusText(wxString::Format(wxT("%.1f %.1f"), yaw, pitch), 1);
00676 }
00677 
00678 void PreviewPanel::mouse2erect(int xm, int ym, double &xd, double & yd)
00679 {
00680     if (m_pano2erect) {
00681         int offsetX=0, offsetY=0;
00682         wxSize sz = GetClientSize();
00683         if (sz.GetWidth() > m_panoImgSize.x) {
00684             offsetX = (sz.GetWidth() - m_panoImgSize.x) / 2;
00685         }
00686         if (sz.GetHeight() > m_panoImgSize.y) {
00687             offsetY = (sz.GetHeight() - m_panoImgSize.y) / 2;
00688         }
00689         double x = xm - offsetX - m_panoImgSize.x/2;
00690         double y = ym - offsetY - m_panoImgSize.y/2;
00691         m_pano2erect->transform(xd, yd, x, y);
00692         //DEBUG_DEBUG("pano: " << x << " " << y << "  erect: " << xd << "° " << yd << "°");
00693      }
00694 }
00695 
00696 void PreviewPanel::DrawOutline(const vector<FDiff2D> & points, wxDC & dc, int offX, int offY)
00697 {
00698     for (vector<FDiff2D>::const_iterator pnt = points.begin();
00699          pnt != points.end() ;
00700          ++pnt)
00701     {
00702         Diff2D point = pnt->toDiff2D();
00703         if (point.x < 0) point.x = 0;
00704         if (point.y < 0) point.y = 0;
00705         if (point.x >= m_panoImgSize.x)
00706             point.x = m_panoImgSize.y-1;
00707         if (point.y >= m_panoImgSize.y)
00708             point.y = m_panoImgSize.y -1;
00709         dc.DrawPoint(roundi(offX + point.x), roundi(offY + point.y));
00710     }
00711 }
00712 
00713 
00714 IMPLEMENT_DYNAMIC_CLASS(PreviewPanel, wxPanel)
00715 
00716         PreviewPanelXmlHandler::PreviewPanelXmlHandler()
00717     : wxXmlResourceHandler()
00718 {
00719     AddWindowStyles();
00720 }
00721 
00722 wxObject *PreviewPanelXmlHandler::DoCreateResource()
00723 {
00724     XRC_MAKE_INSTANCE(cp, PreviewPanel)
00725 
00726             cp->Create(m_parentAsWindow,
00727                        GetID(),
00728                        GetPosition(), GetSize(),
00729                        GetStyle(wxT("style")),
00730                        GetName());
00731 
00732     SetupWindow( cp);
00733 
00734     return cp;
00735 }
00736 
00737 bool PreviewPanelXmlHandler::CanHandle(wxXmlNode *node)
00738 {
00739     return IsOfClass(node, wxT("PreviewPanel"));
00740 }
00741 
00742 IMPLEMENT_DYNAMIC_CLASS(PreviewPanelXmlHandler, wxXmlResourceHandler)
00743 

Generated on 29 Jul 2015 for Hugintrunk by  doxygen 1.4.7