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

Generated on 13 Feb 2016 for Hugintrunk by  doxygen 1.4.7