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/Mapping"), 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::Format(_("Could not stitch preview.\nError: %s\nOne cause could be an invalid or missing image file."), wxString(e.what(), wxConvLocal)),
00405 #ifdef __WXMSW__
00406             wxT("Hugin"),
00407 #else
00408             wxT(""),
00409 #endif
00410             wxOK | wxICON_INFORMATION);
00411     }
00412 
00413 
00414     // update the transform for pano -> erect coordinates
00415     if (m_pano2erect) delete m_pano2erect;
00416     HuginBase::SrcPanoImage src;
00417     src.setProjection(HuginBase::SrcPanoImage::EQUIRECTANGULAR);
00418     src.setHFOV(360);
00419     src.setSize(vigra::Size2D(360,180));
00420     m_pano2erect = new HuginBase::PTools::Transform;
00421     m_pano2erect->createTransform(src, opts);
00422 
00423     if (m_panoBitmap) {
00424         delete m_panoBitmap;
00425     }
00426     m_panoBitmap = new wxBitmap(panoImage);
00427 
00428 
00429     // always redraw
00430     wxClientDC dc(this);
00431     DrawPreview(dc);
00432 
00433     m_state_rendering = false;
00434     DEBUG_DEBUG("m_state_rendering = false");
00435     m_rerender = false;
00436 }
00437 
00438 
00439 void PreviewPanel::DrawPreview(wxDC & dc)
00440 {
00441     if (!IsShown()){
00442         return;
00443     }
00444     DEBUG_TRACE("");
00445 
00446     int offsetX = 0;
00447     int offsetY = 0;
00448 
00449     wxSize sz = GetClientSize();
00450     if (sz.GetWidth() > m_panoImgSize.x) {
00451         offsetX = (sz.GetWidth() - m_panoImgSize.x) / 2;
00452     }
00453     if (sz.GetHeight() > m_panoImgSize.y) {
00454         offsetY = (sz.GetHeight() - m_panoImgSize.y) / 2;
00455     }
00456 
00457     dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
00458     dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
00459     dc.DrawRectangle(0, 0, offsetX, sz.GetHeight());
00460     dc.DrawRectangle(offsetX, 0, sz.GetWidth(), offsetY);
00461     dc.DrawRectangle(offsetX, sz.GetHeight() - offsetY,
00462                      sz.GetWidth(), sz.GetHeight());
00463     dc.DrawRectangle(sz.GetWidth() - offsetX, offsetY,
00464                      sz.GetWidth(), sz.GetHeight() - offsetY);
00465 
00466     // set a clip region to draw stuff accordingly
00467     dc.DestroyClippingRegion();
00468     dc.SetClippingRegion(offsetX, offsetY,
00469                          m_panoImgSize.x, m_panoImgSize.y);
00470 
00471     dc.SetPen(wxPen(wxT("BLACK"), 1, wxPENSTYLE_SOLID));
00472     dc.SetBrush(wxBrush(wxT("BLACK"), wxBRUSHSTYLE_SOLID));
00473     dc.DrawRectangle(offsetX, offsetY, m_panoImgSize.x, m_panoImgSize.y);
00474 
00475 
00476     wxCoord w = m_panoImgSize.x;
00477     wxCoord h = m_panoImgSize.y;
00478 
00479 
00480     // draw panorama image
00481     if (m_panoBitmap) {
00482 
00483         dc.DrawBitmap(*m_panoBitmap, offsetX, offsetY);
00484 
00485         // draw ROI
00486         vigra::Size2D panoSize = pano->getOptions().getSize();
00487         vigra::Rect2D panoROI = pano->getOptions().getROI();
00488         if (panoROI != vigra::Rect2D(panoSize)) {
00489 
00490             double scale = std::min(w/(double)panoSize.x, h/(double)panoSize.y);
00491             vigra::Rect2D previewROI = vigra::Rect2D(panoROI.upperLeft()* scale, panoROI.lowerRight() * scale);
00492             vigra::Rect2D screenROI = previewROI;
00493             screenROI.moveBy(offsetX, offsetY);
00494 
00495 
00496             // TODO: make areas outside ROI darker than the rest of the image
00497             // overdraw areas outside the ROI with some black half transparent
00498             // bitmap
00499             // it seems to be quite complicated to create a half transparent black image...
00500             wxImage blackImg(w,h);
00501             // init alpha channel
00502             if (!blackImg.HasAlpha()) {
00503                 blackImg.InitAlpha();
00504             }
00505             unsigned char * aptr = blackImg.GetAlpha();
00506             unsigned char * aend = aptr + w*h;
00507             for (; aptr != aend; ++aptr)
00508                 *aptr = 128;
00509             wxBitmap blackBitmap(blackImg);
00510 
00511             // left
00512             if (screenROI.left() > offsetX) {
00513                 dc.DestroyClippingRegion();
00514                 dc.SetClippingRegion(offsetX, offsetY,
00515                                      previewROI.left(), h);
00516                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00517             }
00518             // top
00519             if (screenROI.top() > offsetY ) {
00520                 dc.DestroyClippingRegion();
00521                 dc.SetClippingRegion(screenROI.left(), offsetY,
00522                                      previewROI.width(), previewROI.top());
00523                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00524             }
00525             // right
00526             if (screenROI.right() < offsetX + w) {
00527                 dc.DestroyClippingRegion();
00528                 dc.SetClippingRegion(screenROI.right(), offsetY,
00529                                      w - previewROI.right(), h);
00530                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00531             }
00532             // bottom
00533             if (screenROI.bottom() < offsetY + h ) {
00534                 dc.DestroyClippingRegion();
00535                 dc.SetClippingRegion(screenROI.left(), screenROI.bottom(),
00536                                      screenROI.width(), h - previewROI.bottom());
00537                 dc.DrawBitmap(blackBitmap, offsetX, offsetY);
00538             }
00539 
00540 
00541             // reset clipping region
00542             dc.DestroyClippingRegion();
00543             dc.SetClippingRegion(offsetX, offsetY,
00544                          m_panoImgSize.x, m_panoImgSize.y);
00545 
00546             // draw boundaries
00547             dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
00548             dc.SetLogicalFunction(wxINVERT);
00549 
00550             DEBUG_DEBUG("ROI scale factor: " << scale << " screen ROI: " << screenROI);
00551 
00552             dc.DrawLine(screenROI.left(),screenROI.top(),
00553                         screenROI.right(),screenROI.top());
00554             dc.DrawLine(screenROI.right(),screenROI.top(),
00555                         screenROI.right(),screenROI.bottom());
00556             dc.DrawLine(screenROI.right(),screenROI.bottom(),
00557                         screenROI.left(),screenROI.bottom());
00558             dc.DrawLine(screenROI.left(),screenROI.bottom(),
00559                         screenROI.left(),screenROI.top());
00560 
00561 
00562         }
00563     }
00564 
00565     dc.DestroyClippingRegion();
00566     dc.SetClippingRegion(offsetX, offsetY,
00567                     m_panoImgSize.x, m_panoImgSize.y);
00568 
00569     // draw center lines over display
00570     dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
00571     dc.SetLogicalFunction(wxINVERT);
00572     dc.DrawLine(offsetX + w/2, offsetY,
00573                 offsetX + w/2, offsetY + h);
00574     dc.DrawLine(offsetX, offsetY + h/2,
00575                 offsetX + w, offsetY+ h/2);
00576 
00577 }
00578 
00579 void PreviewPanel::OnDraw(wxPaintEvent & event)
00580 {
00581     wxPaintDC dc(this);
00582     DrawPreview(dc);
00583 }
00584 
00585 void PreviewPanel::OnResize(wxSizeEvent & e)
00586 {
00587     DEBUG_TRACE("");
00588     wxSize sz = GetClientSize();
00589     if (sz.GetWidth() != m_panoImgSize.x && sz.GetHeight() != m_panoImgSize.y) {
00590         m_remapCache.invalidate();
00591         if (m_autoPreview) {
00592             ForceUpdate();
00593         }
00594     }
00595 }
00596 
00597 
00598 void PreviewPanel::mousePressLMBEvent(wxMouseEvent & e)
00599 {
00600     DEBUG_DEBUG("mousePressLMBEvent: " << e.m_x << "x" << e.m_y);
00601     double yaw, pitch;
00602     mouse2erect(e.m_x, e.m_y,  yaw, pitch);
00603     // calculate new rotation angles.
00604     Matrix3 rotY;
00605     rotY.SetRotationPT(DEG_TO_RAD(-yaw), 0, 0);
00606     Matrix3 rotP;
00607     rotP.SetRotationPT(0, DEG_TO_RAD(pitch), 0);
00608 
00609     double y,p,r;
00610     Matrix3 rot = rotP * rotY;
00611     rot.GetRotationPT(y,p,r);
00612     y = RAD_TO_DEG(y);
00613     p = RAD_TO_DEG(p);
00614     r = RAD_TO_DEG(r);
00615     DEBUG_DEBUG("rotation angles pitch*yaw: " << y << " " << p << " " << r);
00616 
00617     PanoCommand::GlobalCmdHist::getInstance().addCommand(
00618             new PanoCommand::RotatePanoCmd(*pano, y, p, r)
00619         );
00620     if (!m_autoPreview) {
00621         ForceUpdate();
00622     }
00623 }
00624 
00625 
00626 void PreviewPanel::mousePressRMBEvent(wxMouseEvent & e)
00627 {
00628     DEBUG_DEBUG("mousePressRMBEvent: " << e.m_x << "x" << e.m_y);
00629     double yaw, pitch;
00630     mouse2erect(e.m_x, e.m_y,  yaw, pitch);
00631     // theta, phi: spherical coordinates in mathworld notation.
00632     double theta = DEG_TO_RAD(yaw);
00633     double phi = DEG_TO_RAD(90+pitch);
00634     // convert to cartesian coordinates.
00635 #ifdef DEBUG
00636     double x = cos(theta)* sin(phi);
00637 #endif
00638     double y = sin(theta)* sin(phi);
00639     double z = cos(phi);
00640     DEBUG_DEBUG("theta: " << theta << " phi: " << phi << " x y z:" << x << " " << y << " " << z);
00641     double roll = RAD_TO_DEG(atan(z/y));
00642 
00643     DEBUG_DEBUG("roll correction: " << roll);
00644 
00645     PanoCommand::GlobalCmdHist::getInstance().addCommand(
00646             new PanoCommand::RotatePanoCmd(*pano, 0, 0, roll)
00647         );
00648     if (!m_autoPreview) {
00649         ForceUpdate();
00650     }
00651 }
00652 
00653 
00654 void PreviewPanel::OnMouse(wxMouseEvent & e)
00655 {
00656     double yaw, pitch;
00657     mouse2erect(e.m_x, e.m_y,  yaw, pitch);
00658 
00659     parentWindow->SetStatusText(_("Left click to define new center point, right click to move point to horizon."),0);
00660     parentWindow->SetStatusText(wxString::Format(wxT("%.1f %.1f"), yaw, pitch), 1);
00661 }
00662 
00663 void PreviewPanel::mouse2erect(int xm, int ym, double &xd, double & yd)
00664 {
00665     if (m_pano2erect) {
00666         int offsetX=0, offsetY=0;
00667         wxSize sz = GetClientSize();
00668         if (sz.GetWidth() > m_panoImgSize.x) {
00669             offsetX = (sz.GetWidth() - m_panoImgSize.x) / 2;
00670         }
00671         if (sz.GetHeight() > m_panoImgSize.y) {
00672             offsetY = (sz.GetHeight() - m_panoImgSize.y) / 2;
00673         }
00674         double x = xm - offsetX - m_panoImgSize.x/2;
00675         double y = ym - offsetY - m_panoImgSize.y/2;
00676         m_pano2erect->transform(xd, yd, x, y);
00677         //DEBUG_DEBUG("pano: " << x << " " << y << "  erect: " << xd << "° " << yd << "°");
00678      }
00679 }
00680 
00681 void PreviewPanel::DrawOutline(const std::vector<hugin_utils::FDiff2D> & points, wxDC & dc, int offX, int offY)
00682 {
00683     for (std::vector<hugin_utils::FDiff2D>::const_iterator pnt = points.begin();
00684          pnt != points.end() ;
00685          ++pnt)
00686     {
00687         vigra::Diff2D point = pnt->toDiff2D();
00688         if (point.x < 0) point.x = 0;
00689         if (point.y < 0) point.y = 0;
00690         if (point.x >= m_panoImgSize.x)
00691             point.x = m_panoImgSize.y-1;
00692         if (point.y >= m_panoImgSize.y)
00693             point.y = m_panoImgSize.y -1;
00694         dc.DrawPoint(hugin_utils::roundi(offX + point.x), hugin_utils::roundi(offY + point.y));
00695     }
00696 }
00697 
00698 
00699 IMPLEMENT_DYNAMIC_CLASS(PreviewPanel, wxPanel)
00700 
00701         PreviewPanelXmlHandler::PreviewPanelXmlHandler()
00702     : wxXmlResourceHandler()
00703 {
00704     AddWindowStyles();
00705 }
00706 
00707 wxObject *PreviewPanelXmlHandler::DoCreateResource()
00708 {
00709     XRC_MAKE_INSTANCE(cp, PreviewPanel)
00710 
00711             cp->Create(m_parentAsWindow,
00712                        GetID(),
00713                        GetPosition(), GetSize(),
00714                        GetStyle(wxT("style")),
00715                        GetName());
00716 
00717     SetupWindow( cp);
00718 
00719     return cp;
00720 }
00721 
00722 bool PreviewPanelXmlHandler::CanHandle(wxXmlNode *node)
00723 {
00724     return IsOfClass(node, wxT("PreviewPanel"));
00725 }
00726 
00727 IMPLEMENT_DYNAMIC_CLASS(PreviewPanelXmlHandler, wxXmlResourceHandler)
00728 

Generated on 5 Dec 2016 for Hugintrunk by  doxygen 1.4.7