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

Generated on 21 Nov 2014 for Hugintrunk by  doxygen 1.4.7