Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GLPreviewFrame.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
26 #include <bitset>
27 #include <limits>
28 #include <iostream>
29 
30 #include "hugin_config.h"
31 
32 #if !defined HAVE_EPOXY || !HAVE_EPOXY
33 #include <GL/glew.h>
34 #endif
35 
36 #include "panoinc_WX.h"
37 #include "panoinc.h"
38 #include <wx/msgdlg.h>
39 
40 #include "base_wx/platform.h"
41 #include "base_wx/wxPlatform.h"
42 #include "base_wx/LensTools.h"
49 
51 #include "base_wx/wxPanoCommand.h"
52 
53 #include "hugin/config_defaults.h"
54 #include "hugin/GLPreviewFrame.h"
55 #include "hugin/huginApp.h"
56 #include "hugin/MainFrame.h"
57 #include "hugin/ImagesPanel.h"
58 #include "base_wx/CommandHistory.h"
59 #include "hugin/GLViewer.h"
61 #include "hugin/PanoOperation.h"
62 #include "hugin/PanoOutputDialog.h"
64 #include "base_wx/PTWXDlg.h"
66 #include "vigra_ext/Correlation.h"
69 
70 extern "C" {
71 #include <pano13/queryfeature.h>
72 }
73 
74 #include "ToolHelper.h"
75 #include "Tool.h"
76 #include "DragTool.h"
77 #include "PreviewCropTool.h"
78 #include "PreviewIdentifyTool.h"
79 #include "PreviewCameraTool.h"
80 #include "PreviewDifferenceTool.h"
81 #include "PreviewPanoMaskTool.h"
83 #include "PreviewLayoutLinesTool.h"
84 #include "PreviewColorPickerTool.h"
85 #include "PreviewGuideTool.h"
86 #include "PreviewEditCPTool.h"
87 
88 #include "ProjectionGridTool.h"
89 #include "PanosphereSphereTool.h"
90 
91 #include "OverviewCameraTool.h"
92 #include "OverviewOutlinesTool.h"
93 
94 #include <wx/progdlg.h>
95 #include <wx/infobar.h>
96 
97 // a random id, hope this doesn't break something..
98 enum {
99  ID_TOGGLE_BUT = wxID_HIGHEST+500,
100  PROJ_PARAM_NAMES_ID = wxID_HIGHEST+1300,
101  PROJ_PARAM_VAL_ID = wxID_HIGHEST+1400,
102  PROJ_PARAM_SLIDER_ID = wxID_HIGHEST+1500,
103  PROJ_PARAM_RESET_ID = wxID_HIGHEST+1550,
104  ID_TOGGLE_BUT_LEAVE = wxID_HIGHEST+1600,
105  ID_FULL_SCREEN = wxID_HIGHEST+1710,
106  ID_SHOW_ALL = wxID_HIGHEST+1711,
107  ID_SHOW_NONE = wxID_HIGHEST+1712,
108  ID_HIDE_HINTS = wxID_HIGHEST+1715,
109  ID_ASSISTANT_MENU = wxID_HIGHEST+1800,
110  ID_CREATEPANO_MENU = wxID_HIGHEST+1810,
111  ID_ASS_LOAD_IMAGES = wxID_HIGHEST+1820
112 };
113 
115 enum{
122 };
123 
124 //------------------------------------------------------------------------------
125 #define PF_STYLE (wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN)
126 
127 GLwxAuiFloatingFrame* GLwxAuiManager::CreateFloatingFrame(wxWindow* parent, const wxAuiPaneInfo& p)
128 {
129  DEBUG_DEBUG("CREATING FLOATING FRAME");
130  frame->PauseResize();
131  GLwxAuiFloatingFrame* fl_frame = new GLwxAuiFloatingFrame(parent, this, p);
132  DEBUG_DEBUG("CREATED FLOATING FRAME");
133  return fl_frame;
134 }
135 
136 GLwxAuiFloatingFrame::GLwxAuiFloatingFrame(wxWindow* parent, GLwxAuiManager* owner_mgr, const wxAuiPaneInfo& pane, wxWindowID id, long style) :
137  wxAuiFloatingFrame(parent, (wxAuiManager*)owner_mgr, pane, id, style)
138 {
139  Bind(wxEVT_ACTIVATE, &GLwxAuiFloatingFrame::OnActivate, this);
140 }
141 
142 void GLwxAuiFloatingFrame::OnActivate(wxActivateEvent& evt)
143 {
144  DEBUG_DEBUG("FRAME ACTIVATE");
145  GLPreviewFrame * frame = ((GLwxAuiManager*) GetOwnerManager())->getPreviewFrame();
146  frame->ContinueResize();
147  evt.Skip();
148 }
149 
151 {
152  DEBUG_DEBUG("FRAME ON MOVE FINISHED");
153  GLPreviewFrame * frame = ((GLwxAuiManager*) GetOwnerManager())->getPreviewFrame();
154  frame->PauseResize();
155  wxAuiFloatingFrame::OnMoveFinished();
156  DEBUG_DEBUG("FRAME AFTER ON MOVE FINISHED");
157 }
158 
160 {
161  DEBUG_DEBUG("PAUSE RESIZE");
162  GLresize = false;
163 }
164 
166 {
167  GLresize = true;
168  wxSizeEvent event = wxSizeEvent(wxSize());
169  m_GLPreview->Resized(event);
170  m_GLOverview->Resized(event);
171 }
172 
173 #include <iostream>
175  : wxFrame(frame,-1, _("Fast Panorama preview"), wxDefaultPosition, wxDefaultSize,
176  PF_STYLE),
177  m_pano(pano)
178 {
179 
180  DEBUG_TRACE("");
181 
182  // initialize pointer
183  preview_helper = NULL;
185  plane_overview_helper = NULL;
186  crop_tool = NULL;
187  drag_tool = NULL;
188  color_picker_tool = NULL;
189  edit_cp_tool = NULL;
190  overview_drag_tool = NULL;
191  identify_tool = NULL ;
192  camera_tool = NULL;
195  difference_tool = NULL;
196  plane_difference_tool = NULL;
198  pano_mask_tool = NULL;
199  preview_guide_tool = NULL;
201 #ifdef __WXGTK__
202  loadedLayout=false;
203 #endif
204 
205  m_mode = -1;
206  m_oldProjFormat = -1;
207  // add a status bar
208  CreateStatusBar(3);
209  int widths[3] = {-3, 150, 150};
210  SetStatusWidths(3, widths);
211  SetStatusText(wxEmptyString,1);
212  SetStatusText(wxEmptyString,2);
213  wxConfigBase * cfg = wxConfigBase::Get();
214 
215  wxPanel *tool_panel = wxXmlResource::Get()->LoadPanel(this,"mode_panel");
216  XRCCTRL(*this,"preview_center_tool",wxButton)->SetBitmapMargins(0,5);
217  XRCCTRL(*this,"preview_fit_pano_tool",wxButton)->SetBitmapMargins(0,5);
218  XRCCTRL(*this,"preview_straighten_pano_tool",wxButton)->SetBitmapMargins(0,5);
219  XRCCTRL(*this,"preview_fit_pano_tool2",wxButton)->SetBitmapMargins(0,5);
220  XRCCTRL(*this,"preview_autocrop_tool",wxButton)->SetBitmapMargins(0,5);
221  XRCCTRL(*this,"preview_stack_autocrop_tool",wxButton)->SetBitmapMargins(0,5);
222  XRCCTRL(*this, "preview_autocrop_outside_tool", wxButton)->SetBitmapMargins(0, 5);
223 
224  m_tool_notebook = XRCCTRL(*this, "mode_toolbar_notebook", wxNotebook);
225  m_tool_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &GLPreviewFrame::OnSelectMode, this);
226  m_tool_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, &GLPreviewFrame::OnToolModeChanging, this);
227  m_identify_togglebutton = XRCCTRL(*this, "preview_identify_toggle_button", wxToggleButton);
228  m_identify_togglebutton->SetBitmapMargins(0, 5);
229  m_identify_togglebutton->Bind(wxEVT_TOGGLEBUTTON, &GLPreviewFrame::OnIdentify, this);
230  m_colorpicker_togglebutton = XRCCTRL(*this, "preview_color_picker_toggle_button", wxToggleButton);
231  m_colorpicker_togglebutton->SetBitmapMargins(0, 5);
232  m_colorpicker_togglebutton->Bind(wxEVT_TOGGLEBUTTON, &GLPreviewFrame::OnColorPicker, this);
233  m_editCP_togglebutton = XRCCTRL(*this, "preview_edit_cp_toggle_button", wxToggleButton);
234  m_editCP_togglebutton->SetBitmapMargins(0, 5);
235  m_editCP_togglebutton->Bind(wxEVT_TOGGLEBUTTON, &GLPreviewFrame::OnEditCPTool, this);
236 
237  //build menu bar
238 #ifdef __WXMAC__
239  wxApp::s_macExitMenuItemId = XRCID("action_exit_preview");
240 #endif
241  wxMenuBar* simpleMenu=wxXmlResource::Get()->LoadMenuBar(this, "preview_simple_menu");
242  m_filemenuSimple=wxXmlResource::Get()->LoadMenu("preview_file_menu");
243  m_filemenuAdvanced = wxXmlResource::Get()->LoadMenu("preview_file_menu_advanced");
244  MainFrame::Get()->GetFileHistory()->UseMenu(m_filemenuSimple->FindItem(XRCID("menu_mru_preview"))->GetSubMenu());
245  MainFrame::Get()->GetFileHistory()->UseMenu(m_filemenuAdvanced->FindItem(XRCID("menu_mru_preview"))->GetSubMenu());
246  MainFrame::Get()->GetFileHistory()->AddFilesToMenu();
247  simpleMenu->Insert(0, m_filemenuSimple, _("&File"));
248  SetMenuBar(simpleMenu);
249 
250  // initialize preview background color
251  wxString c = cfg->Read("/GLPreviewFrame/PreviewBackground",HUGIN_PREVIEW_BACKGROUND);
252  m_preview_background_color = wxColour(c);
253  XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->SetColour(m_preview_background_color);
254  XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->Refresh();
255  XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->Update();
256 
257  m_topsizer = new wxBoxSizer( wxVERTICAL );
258 
259  wxPanel * toggle_panel = new wxPanel(this);
260 
261  bool overview_hidden;
262  cfg->Read("/GLPreviewFrame/overview_hidden", &overview_hidden, false);
263  GetMenuBar()->FindItem(XRCID("action_show_overview"))->Check(!overview_hidden);
264 
265  m_ToggleButtonSizer = new wxStaticBoxSizer(
266  new wxStaticBox(toggle_panel, -1, _("displayed images")),
267  wxHORIZONTAL );
268  toggle_panel->SetSizer(m_ToggleButtonSizer);
269 
270  m_ButtonPanel = new wxScrolledWindow(toggle_panel, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
271  //Horizontal scroll bars only
272  m_ButtonPanel->SetScrollRate(10, 0);
273  m_ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
274  m_ButtonPanel->SetAutoLayout(true);
275  m_ButtonPanel->SetSizer(m_ButtonSizer);
276 
277  wxPanel *panel = new wxPanel(toggle_panel);
278  wxBitmapBundle bitmapBundle=wxBitmapBundle::FromSVGFile(huginApp::Get()->GetXRCPath() + "data/preview_show_all.svg", wxSize(32, 32));
279  m_selectAllButton = new SplitButton(panel, ID_SHOW_ALL, _("All"), wxDefaultPosition, wxDefaultSize);
280  m_selectAllButton->SetBitmap(bitmapBundle);
281  //m_selectAllButton->SetBitmapMargins(5, 0);
282  m_selectAllButton->LoadMenu("preview_select_menu");
283  m_selectAllButton->Bind(wxEVT_BUTTON, &GLPreviewFrame::OnShowAll, this);
284  // read last used setting
285  long mode = cfg->Read("/GLPreviewFrame/SelectAllMode", 0l);
286  m_selectAllMode = static_cast<SelectAllMode>(mode);
287  switch (m_selectAllMode)
288  {
290  m_selectAllButton->GetSplitButtonMenu()->Check(XRCID("selectMenu_selectMedian"), true);
291  break;
293  m_selectAllButton->GetSplitButtonMenu()->Check(XRCID("selectMenu_selectDarkest"), true);
294  break;
296  m_selectAllButton->GetSplitButtonMenu()->Check(XRCID("selectMenu_selectBrightest"), true);
297  break;
298  case SELECT_ALL_IMAGES:
299  default:
300  m_selectAllButton->GetSplitButtonMenu()->Check(XRCID("selectMenu_selectAll"), true);
301  break;
302  };
303  m_selectKeepSelection = (cfg->Read("/GLPreviewFrame/SelectAllKeepSelection", 1l) == 1l);
305  {
306  m_selectAllButton->GetSplitButtonMenu()->Check(XRCID("selectMenu_keepCurrentSelection"), true);
307  }
308  else
309  {
310  m_selectAllButton->GetSplitButtonMenu()->Check(XRCID("selectMenu_resetSelection"), true);
311  };
312  bitmapBundle=wxBitmapBundle::FromSVGFile(huginApp::Get()->GetXRCPath() + "data/preview_show_none.svg", wxSize(32, 32));
313  wxButton* select_none = new wxButton(panel, ID_SHOW_NONE, _("None"));
314  select_none->SetBitmap(bitmapBundle, wxLEFT);
315  select_none->SetBitmapMargins(5,0);
316  select_none->Bind(wxEVT_BUTTON, &GLPreviewFrame::OnShowNone, this);
317 
318  wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
319  sizer->Add(m_selectAllButton,0,wxALIGN_CENTER_VERTICAL | wxLEFT | wxTOP | wxBOTTOM,5);
320  sizer->Add(select_none,0,wxALIGN_CENTER_VERTICAL | wxRIGHT | wxTOP | wxBOTTOM,5);
321  panel->SetSizer(sizer);
322  m_ToggleButtonSizer->Add(panel, 0, wxALIGN_CENTER_VERTICAL);
323  m_ToggleButtonSizer->Add(m_ButtonPanel, 1, wxALIGN_CENTER_VERTICAL, 0);
324 
325  m_topsizer->Add(tool_panel, 0, wxEXPAND | wxALL, 2);
326  m_topsizer->Add(toggle_panel, 0, wxEXPAND | wxBOTTOM, 5);
327 
328  m_infoBar = new wxInfoBar(this);
329  m_infoBar->AddButton(ID_HIDE_HINTS,_("Hide"));
331  m_topsizer->Add(m_infoBar, 0, wxEXPAND);
332 
333  //create panel that will hold gl canvases
334  wxPanel * vis_panel = new wxPanel(this);
335 
336  wxPanel * preview_panel = new wxPanel(vis_panel);
337  wxPanel * overview_panel = new wxPanel(vis_panel);
338 
339  // create our Viewers
340  int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0};
341  m_GLPreview = new GLPreview(preview_panel, pano, args, this);
342  m_GLOverview = new GLOverview(overview_panel, pano, args, this, m_GLPreview->GetContext());
344 
345 #ifdef __WXGTK__
346  // on wxGTK we can not create the OpenGL context with a hidden window
347  // therefore we need to create the overview window open and later hide it
348  overview_hidden=false;
349 #endif
350  m_GLOverview->SetActive(!overview_hidden);
351 
352  // set the AUI manager to our panel
354  m_mgr->SetManagedWindow(vis_panel);
355  vis_panel->SetMinSize(wxSize(200,150));
356 
357  //create the sizer for the preview
358  wxFlexGridSizer * flexSizer = new wxFlexGridSizer(2,0,5,5);
359  flexSizer->AddGrowableCol(0);
360  flexSizer->AddGrowableRow(0);
361 
362  //overview sizer
363  wxBoxSizer * overview_sizer = new wxBoxSizer(wxVERTICAL);
364 
365 
366  flexSizer->Add(m_GLPreview,
367  1, // not vertically stretchable
368  wxEXPAND | // horizontally stretchable
369  wxALL, // draw border all around
370  5); // border width
371 
372  m_VFOVSlider = new wxSlider(preview_panel, -1, 1,
373  1, 180,
374  wxDefaultPosition, wxDefaultSize,
375  wxSL_VERTICAL | wxSL_AUTOTICKS,
376  wxDefaultValidator,
377  _("VFOV"));
378  m_VFOVSlider->SetLineSize(1);
379  m_VFOVSlider->SetPageSize(10);
380  m_VFOVSlider->SetTickFreq(5);
381  m_VFOVSlider->SetToolTip(_("drag to change the vertical field of view"));
382  m_VFOVSlider->Bind(wxEVT_SCROLL_CHANGED, [this](wxScrollEvent& e) {
384  opt.setVFOV(e.GetInt());
386  }
387  );
388 #ifdef __WXMAC__
389  m_VFOVSlider->Bind(wxEVT_SCROLL_THUMBRELEASE, [this](wxScrollEvent& e) {
391  opt.setVFOV(e.GetInt());
393  }
394  );
395 #endif
396  m_VFOVSlider->Bind(wxEVT_SCROLL_THUMBTRACK, [this](wxScrollEvent& e) {
398  opt.setVFOV(e.GetInt());
399  // we only actually update the panorama fully when the mouse is released.
400  // As we are dragging it we don't want to create undo events, but we would
401  // like to update the display, so we change the GLViewer's ViewState and
402  // request a redraw.
404  m_GLPreview->Refresh();
405  }
406  );
407 
408  flexSizer->Add(m_VFOVSlider, 0, wxEXPAND);
409 
410  m_HFOVSlider = new wxSlider(preview_panel, -1, 1,
411  1, 360,
412  wxDefaultPosition, wxDefaultSize,
413  wxSL_HORIZONTAL | wxSL_AUTOTICKS,
414  wxDefaultValidator,
415  _("HFOV"));
416  m_HFOVSlider->SetPageSize(10);
417  m_HFOVSlider->SetLineSize(1);
418  m_HFOVSlider->SetTickFreq(5);
419 
420  m_HFOVSlider->SetToolTip(_("drag to change the horizontal field of view"));
421  m_HFOVSlider->Bind(wxEVT_SCROLL_CHANGED, [this](wxScrollEvent& e) {
423  opt.setHFOV(e.GetInt());
425  }
426  );
427 #ifdef __WXMAC__
428  m_HFOVSlider->Bind(wxEVT_SCROLL_THUMBRELEASE, [this](wxScrollEvent& e) {
430  opt.setHFOV(e.GetInt());
432  }
433  );
434 #endif
435  m_HFOVSlider->Bind(wxEVT_SCROLL_THUMBTRACK, [this](wxScrollEvent& e) {
437  opt.setHFOV(e.GetInt());
438  // we only actually update the panorama fully when the mouse is released.
439  // As we are dragging it we don't want to create undo events, but we would
440  // like to update the display, so we change the GLViewer's ViewState and
441  // request a redraw.
443  m_GLPreview->Refresh();
444  }
445  );
446 
447  m_HFOVText = XRCCTRL(*this, "pano_text_hfov" ,wxTextCtrl);
449  m_HFOVText->PushEventHandler(new TextKillFocusHandler(this));
450  m_HFOVText->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnHFOVChanged, this);
451  m_VFOVText = XRCCTRL(*this, "pano_text_vfov" ,wxTextCtrl);
453  m_VFOVText->PushEventHandler(new TextKillFocusHandler(this));
454  m_VFOVText->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnVFOVChanged, this);
455 
456  m_ROILeftTxt = XRCCTRL(*this, "pano_val_roi_left", wxTextCtrl);
458  m_ROILeftTxt->PushEventHandler(new TextKillFocusHandler(this));
459  m_ROILeftTxt->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnROIChanged, this);
460 
461  m_ROIRightTxt = XRCCTRL(*this, "pano_val_roi_right", wxTextCtrl);
463  m_ROIRightTxt->PushEventHandler(new TextKillFocusHandler(this));
464  m_ROIRightTxt->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnROIChanged, this);
465 
466  m_ROITopTxt = XRCCTRL(*this, "pano_val_roi_top", wxTextCtrl);
468  m_ROITopTxt->PushEventHandler(new TextKillFocusHandler(this));
469  m_ROITopTxt->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnROIChanged, this);
470 
471  m_ROIBottomTxt = XRCCTRL(*this, "pano_val_roi_bottom", wxTextCtrl);
473  m_ROIBottomTxt->PushEventHandler(new TextKillFocusHandler(this));
474  m_ROIBottomTxt->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnROIChanged, this);
475 
476  m_GuideChoiceCrop = XRCCTRL(*this, "preview_guide_choice_crop", wxChoice);
477  m_GuideChoiceProj = XRCCTRL(*this, "preview_guide_choice_proj", wxChoice);
478  m_GuideChoiceDrag = XRCCTRL(*this, "preview_guide_choice_drag", wxChoice);
479  int guide=cfg->Read("/GLPreviewFrame/guide",0l);
480  m_GuideChoiceCrop->SetSelection(guide);
481  m_GuideChoiceProj->SetSelection(guide);
482  m_GuideChoiceDrag->SetSelection(guide);
483  m_GuideChoiceCrop->Bind(wxEVT_CHOICE, &GLPreviewFrame::OnGuideChanged, this);
484  m_GuideChoiceProj->Bind(wxEVT_CHOICE, &GLPreviewFrame::OnGuideChanged, this);
485  m_GuideChoiceDrag->Bind(wxEVT_CHOICE, &GLPreviewFrame::OnGuideChanged, this);
486 
487  flexSizer->Add(m_HFOVSlider, 0, wxEXPAND);
488 
489  m_overviewCommandPanel = wxXmlResource::Get()->LoadPanel(overview_panel,"overview_command_panel");
490  m_OverviewModeChoice = XRCCTRL(*this, "overview_mode_choice", wxChoice);
492  const wxSize dpiSize(m_overviewCommandPanel->FromDIP(wxSize(200, 20)));
493  m_overviewCommandPanel->SetSize(0, 0, dpiSize.GetWidth(), dpiSize.GetHeight(), wxSIZE_AUTO_WIDTH);
494 
495  overview_sizer->Add(m_overviewCommandPanel, 0, wxEXPAND);
496  overview_sizer->Add(m_GLOverview, 1, wxEXPAND);
497 
498  bool showGrid;
499  cfg->Read("/GLPreviewFrame/showPreviewGrid",&showGrid,true);
500  GetMenuBar()->FindItem(XRCID("action_show_grid"))->Check(showGrid);
501 
502  preview_panel->SetSizer(flexSizer);
503  overview_panel->SetSizer(overview_sizer);
504 
505  m_mgr->AddPane(preview_panel,
506  wxAuiPaneInfo(
507  ).Name("preview"
508  ).MinSize(300,200
509  ).CloseButton(false
510  ).CaptionVisible(false
511  ).Caption(_("Preview")
512  ).Floatable(false
513  ).Dockable(false
514  ).Center(
515  )
516  );
517 
518  m_mgr->AddPane(overview_panel,
519  wxAuiPaneInfo(
520  ).Name("overview"
521  ).MinSize(300,200
522  ).CloseButton(false
523  ).CaptionVisible(
524  ).Caption(_("Overview")
525  ).FloatingSize(100,100
526  ).FloatingPosition(500,500
527  ).Dockable(true
528  ).PinButton(
529  ).Left(
530  ).Show(!overview_hidden
531  )
532  );
533 
534 
535  m_topsizer->Add(vis_panel, 1, wxEXPAND);
536 
537  //assistant related controls
538  m_loadImagesButton = XRCCTRL(*this, "ass_load_images_button", SplitButton);
540  m_loadImagesButton->GetSplitButtonMenu()->Append(ID_ASS_LOAD_IMAGES, _("Load images (autodetect lens type)..."));
541  // event handler for main button
542  m_loadImagesButton->Bind(wxEVT_BUTTON, &GLPreviewFrame::OnLoadImages, this);
543  // event handler for first menu item with automatic lens type detection
544  Bind(wxEVT_MENU, &GLPreviewFrame::OnLoadImages, this, ID_ASS_LOAD_IMAGES);
545  m_loadImagesButton->GetSplitButtonMenu()->AppendSeparator();
546  // now add all lens types to menu
548  int lensTypeId = ID_ASS_LOAD_IMAGES + 1;
549  for (auto& lensType : lensInfoVector)
550  {
551  m_loadImagesButton->GetSplitButtonMenu()->Append(lensTypeId, wxString::Format(_("Load images (lens type: %s)..."), lensType.name));
552  const int lensId = lensType.id;
553  Bind(wxEVT_MENU, [this, lensId](wxCommandEvent&) { LoadImages(lensId); }, lensTypeId);
554  ++lensTypeId;
555  };
556 
557  m_alignButton = XRCCTRL(*this, "ass_align_button", SplitButton);
559  m_alignButton->Disable();
560  // add default assistant to drop down menu
561  m_alignButton->GetSplitButtonMenu()->Append(ID_ASSISTANT_MENU, _("Panorama assistant (default)"), m_alignButton->GetToolTipText());
562  // event handler for main button
563  m_alignButton->Bind(wxEVT_BUTTON, &GLPreviewFrame::OnAlign, this);
564  // event handler for first menu item - default align
565  Bind(wxEVT_MENU, &GLPreviewFrame::OnAlign, this, ID_ASSISTANT_MENU);
566  m_alignButton->GetSplitButtonMenu()->AppendSeparator();
567  // provide help texts in the status bar, add the necessary event handlers
568  m_alignButton->GetSplitButtonMenu()->Bind(wxEVT_MENU_CLOSE, [this](wxMenuEvent& e) { SetStatusText(wxString()); });
569  m_alignButton->GetSplitButtonMenu()->Bind(wxEVT_MENU_HIGHLIGHT,
570  [this](wxMenuEvent& e) { if (e.GetId() > 0) SetStatusText(m_alignButton->GetSplitButtonMenu()->GetHelpString(e.GetId())); }
571  );
572 
573  m_createButton = XRCCTRL(*this, "ass_create_button", SplitButton);
575  m_createButton->Disable();
576  // add default create function to drop down menu
577  m_createButton->GetSplitButtonMenu()->Append(ID_CREATEPANO_MENU, _("Stitch normal panorama (default)"), m_createButton->GetToolTipText());
578  // event handler for main button
579  m_createButton->Bind(wxEVT_BUTTON, &GLPreviewFrame::OnCreate, this);
580  // event handler for first menu item
581  Bind(wxEVT_MENU, &GLPreviewFrame::OnCreate, this, ID_CREATEPANO_MENU);
582  m_createButton->GetSplitButtonMenu()->AppendSeparator();
583  // provide help texts in the status bar, add the necessary event handlers
584  m_createButton->GetSplitButtonMenu()->Bind(wxEVT_MENU_CLOSE, [this](wxMenuEvent& e) { SetStatusText(wxString()); });
585  m_createButton->GetSplitButtonMenu()->Bind(wxEVT_MENU_HIGHLIGHT,
586  [this](wxMenuEvent& e) { if (e.GetId() > 0) SetStatusText(m_createButton->GetSplitButtonMenu()->GetHelpString(e.GetId())); }
587  );
588 
589  m_ProjectionChoice = XRCCTRL(*this,"projection_choice",wxChoice);
590 
591  /* populate with all available projection types */
592  int nP = panoProjectionFormatCount();
593  for(int n=0; n < nP; n++) {
594  pano_projection_features proj;
595  if (panoProjectionFeaturesQuery(n, &proj)) {
596  wxString str2(proj.name, wxConvLocal);
597  m_ProjectionChoice->Append(wxGetTranslation(str2));
598  }
599  }
600  m_ProjectionChoice->SetSelection(2);
601  m_ProjectionChoice->Bind(wxEVT_CHOICE, &GLPreviewFrame::OnProjectionChoice, this);
602 
604  // Blend mode
605  // remaining blend mode should be added after OpenGL context has been created
606  // see FillBlendMode()
607  m_differenceIndex = -1;
608  // create choice item
609  m_BlendModeChoice = XRCCTRL(*this,"blend_mode_choice",wxChoice);
610  m_BlendModeChoice->Append(_("normal"));
611  m_BlendModeChoice->SetSelection(0);
612  m_BlendModeChoice->Bind(wxEVT_CHOICE, &GLPreviewFrame::OnBlendChoice, this);
613 
614  m_DragModeChoice = XRCCTRL(*this, "drag_mode_choice", wxChoice);
616  bool individualDrag;
617  cfg->Read("/GLPreviewFrame/individualDragMode", &individualDrag, false);
618  if(individualDrag)
619  {
620  m_DragModeChoice->SetSelection(1);
621  }
622  else
623  {
624  m_DragModeChoice->SetSelection(0);
625  };
626  m_DragModeChoice->Bind(wxEVT_CHOICE, &GLPreviewFrame::OnDragChoice, this);
627  // default drag mode
629 
630  // TODO implement hdr display in OpenGL, if possible?
631  // Disabled until someone can figure out HDR display in OpenGL.
632  /*
634  // LDR, HDR
635  blendModeSizer->Add(new wxStaticText(this, -1, _("Output:")),
636  0, // not vertically strechable
637  wxALL | wxALIGN_CENTER_VERTICAL, // draw border all around
638  5); // border width
639 
640  m_choices[0] = _("LDR");
641  m_choices[1] = _("HDR");
642  m_outputModeChoice = new wxChoice(this, ID_OUTPUTMODE_CHOICE,
643  wxDefaultPosition, wxDefaultSize,
644  2, m_choices);
645  m_outputModeChoice->SetSelection(0);
646  blendModeSizer->Add(m_outputModeChoice,
647  0,
648  wxALL | wxALIGN_CENTER_VERTICAL,
649  5);
650  */
651 
653  // exposure
654  m_defaultExposureBut = XRCCTRL(*this, "exposure_default_button", wxBitmapButton);
655  m_defaultExposureBut->Bind(wxEVT_BUTTON, &GLPreviewFrame::OnDefaultExposure, this);
656 
657  m_exposureTextCtrl = XRCCTRL(*this, "exposure_text", wxTextCtrl);
658  m_exposureTextCtrl->PushEventHandler(new TextKillFocusHandler(this));
659  m_exposureTextCtrl->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnExposureChanged, this);
660 
661  m_exposureSpinBut = XRCCTRL(*this, "exposure_spin", wxSpinButton);
662  m_exposureSpinBut->SetValue(0);
663  m_exposureSpinBut->SetMaxSize(wxSize(-1, m_exposureTextCtrl->GetSize().GetHeight()));
664  m_exposureSpinBut->Bind(wxEVT_SPIN_DOWN, &GLPreviewFrame::OnDecreaseExposure, this);
665  m_exposureSpinBut->Bind(wxEVT_SPIN_UP, &GLPreviewFrame::OnIncreaseExposure, this);
666 
667  m_rangeCompressionTextCtrl = XRCCTRL(*this, "range_compression_text", wxTextCtrl);
668  m_rangeCompressionTextCtrl->PushEventHandler(new TextKillFocusHandler(this));
670 
671  m_rangeCompressionSpinBut = XRCCTRL(*this, "range_compression_spin", wxSpinButton);
672  m_rangeCompressionSpinBut->SetValue(0);
673  m_rangeCompressionSpinBut->SetMaxSize(wxSize(-1, m_rangeCompressionTextCtrl->GetSize().GetHeight()));
676 
677  m_projection_panel = XRCCTRL(*this, "projection_panel", wxPanel);
678  m_projParamSizer = new wxBoxSizer(wxHORIZONTAL);
679 
680  wxBitmapButton * resetProjButton=new wxBitmapButton(m_projection_panel, PROJ_PARAM_RESET_ID,
681  wxArtProvider::GetBitmap(wxART_REDO));
682  resetProjButton->SetToolTip(_("Resets the projection's parameters to their default values."));
683  resetProjButton->Bind(wxEVT_BUTTON, &GLPreviewFrame::OnProjParameterReset, this);
684  m_projParamSizer->Add(resetProjButton, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
685 
686  m_projParamNamesLabel.resize(PANO_PROJECTION_MAX_PARMS);
687  m_projParamTextCtrl.resize(PANO_PROJECTION_MAX_PARMS);
688  m_projParamSlider.resize(PANO_PROJECTION_MAX_PARMS);
689 
690  for (int i=0; i < PANO_PROJECTION_MAX_PARMS; i++) {
691 
692  wxBoxSizer* paramBoxSizer = new wxBoxSizer(wxVERTICAL);
693  m_projParamNamesLabel[i] = new wxStaticText(m_projection_panel, PROJ_PARAM_NAMES_ID+i, _("param:"));
694  paramBoxSizer->Add(m_projParamNamesLabel[i],
695  0, // not vertically strechable
696  wxLEFT | wxRIGHT, // draw border all around
697  5); // border width
698  m_projParamTextCtrl[i] = new wxTextCtrl(m_projection_panel, PROJ_PARAM_VAL_ID+i, "0",
699  wxDefaultPosition, wxSize(35,-1), wxTE_PROCESS_ENTER);
700  m_projParamTextCtrl[i]->PushEventHandler(new TextKillFocusHandler(this));
701  m_projParamTextCtrl[i]->Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnProjParameterChanged, this);
702  paramBoxSizer->Add(m_projParamTextCtrl[i],
703  0, // not vertically strechable
704  wxLEFT | wxRIGHT, // draw border all around
705  5); // border width
706 
707  m_projParamSizer->Add(paramBoxSizer);
708  m_projParamSlider[i] = new wxSlider(m_projection_panel, PROJ_PARAM_SLIDER_ID+i, 0, -90, 90);
709  m_projParamSlider[i]->Bind(wxEVT_SCROLL_CHANGED, &GLPreviewFrame::OnChangeProjectionParam, this);
710 #ifdef __WXMAC__
711  m_projParamSlider[i]->Bind(wxEVT_SCROLL_THUMBRELEASE, &GLPreviewFrame::OnChangeProjectionParam, this);
712 #endif
713  m_projParamSlider[i]->Bind(wxEVT_SCROLL_THUMBTRACK, &GLPreviewFrame::OnTrackChangeProjectionParam, this);
714 
716  1, // not vertically strechable
717  wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL , // draw border all around
718  5); // border width
719  }
720 
721  m_projection_panel->GetSizer()->Add(m_projParamSizer, 1, wxALIGN_CENTER_VERTICAL);
722 
723  // do not show projection param sizer
724  m_projection_panel->GetSizer()->Show(m_projParamSizer, false, true);
725 
726  // the initial size as calculated by the sizers
727  this->SetSizer( m_topsizer );
728  m_topsizer->SetSizeHints( this );
729 
730  // set the minimize icon
731 #ifdef __WXMSW__
732  wxIconBundle myIcons(huginApp::Get()->GetXRCPath() + "data/hugin.ico",wxBITMAP_TYPE_ICO);
733  SetIcons(myIcons);
734 #else
735  wxIcon myIcon(huginApp::Get()->GetXRCPath() + "data/hugin.png",wxBITMAP_TYPE_PNG);
736  SetIcon(myIcon);
737 #endif
738 
739  m_pano.addObserver(this);
740 
741  hugin_utils::RestoreFramePosition(this, "GLPreviewFrame");
742 
743 #ifdef __WXMSW__
744  // wxFrame does have a strange background color on Windows..
745  this->SetBackgroundColour(m_GLPreview->GetBackgroundColour());
746 #endif
747 
748  m_showProjectionHints = cfg->Read("/GLPreviewFrame/ShowProjectionHints", HUGIN_SHOW_PROJECTION_HINTS) == 1;
749  m_degDigits = wxConfigBase::Get()->Read("/General/DegreeFractionalDigitsEdit",3);
750 
751  // tell the manager to "commit" all the changes just made
752  m_mgr->Update();
753  // build context menu for images button
754  m_removeImageMenuId = m_imageMenu.Append(wxID_ANY, "Remove image")->GetId();
756 
757  // bind event handlers
758  Bind(wxEVT_CLOSE_WINDOW, &GLPreviewFrame::OnClose, this);
759  Bind(wxEVT_SHOW, &GLPreviewFrame::OnShowEvent, this);
760  Bind(wxEVT_MENU_CLOSE, [this](wxMenuEvent& e) { m_GLPreview->Refresh(); e.Skip();});
761  Bind(wxEVT_SLIDER, &GLPreviewFrame::OnLayoutScaleChange, this, XRCID("layout_scale_slider"));
762  Bind(wxEVT_COLOURPICKER_CHANGED, &GLPreviewFrame::OnPreviewBackgroundColorChanged, this, XRCID("preview_background"));
763  // handler for menu items
764  Bind(wxEVT_MENU, &GLPreviewFrame::OnOverviewToggle, this, XRCID("action_show_overview"));
765  Bind(wxEVT_MENU, &GLPreviewFrame::OnSwitchPreviewGrid, this, XRCID("action_show_grid"));
766  Bind(wxEVT_MENU, &GLPreviewFrame::OnFullScreen, this, XRCID("ID_SHOW_FULL_SCREEN_PREVIEW"));
767  Bind(wxEVT_MENU, &GLPreviewFrame::OnShowMainFrame, this, XRCID("action_show_main_frame"));
768  Bind(wxEVT_MENU, &GLPreviewFrame::OnUserExit, this, XRCID("action_exit_preview"));
769  // context menu of select all button
770  Bind(wxEVT_MENU, &GLPreviewFrame::OnSelectAllMenu, this, XRCID("selectMenu_selectAll"));
771  Bind(wxEVT_MENU, &GLPreviewFrame::OnSelectMedianMenu, this, XRCID("selectMenu_selectMedian"));
772  Bind(wxEVT_MENU, &GLPreviewFrame::OnSelectDarkestMenu, this, XRCID("selectMenu_selectBrightest"));
773  Bind(wxEVT_MENU, &GLPreviewFrame::OnSelectBrightestMenu, this, XRCID("selectMenu_selectDarkest"));
774  Bind(wxEVT_MENU, &GLPreviewFrame::OnSelectKeepSelection, this, XRCID("selectMenu_keepCurrentSelection"));
775  Bind(wxEVT_MENU, &GLPreviewFrame::OnSelectResetSelection, this, XRCID("selectMenu_resetSelection"));
776  // handler for different buttons
777  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnCenterHorizontally, this, XRCID("preview_center_tool"));
778  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnFitPano, this, XRCID("preview_fit_pano_tool"));
779  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnFitPano, this, XRCID("preview_fit_pano_tool2"));
780  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnStraighten, this, XRCID("preview_straighten_pano_tool"));
781  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnNumTransform, this, XRCID("apply_num_transform"));
782  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnAutocrop, this, XRCID("preview_autocrop_tool"));
783  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnStackAutocrop, this, XRCID("preview_stack_autocrop_tool"));
784  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnAutocropOutside, this, XRCID("preview_autocrop_outside_tool"));
785  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnResetCrop, this, XRCID("reset_crop_button"));
786  Bind(wxEVT_BUTTON, &GLPreviewFrame::OnSetCropAspect, this, XRCID("crop_aspect_button"));
787  //checkboxes
788  Bind(wxEVT_CHECKBOX, &GLPreviewFrame::OnPhotometric, this, XRCID("preview_photometric_tool"));
789  Bind(wxEVT_CHECKBOX, &GLPreviewFrame::OnControlPoint, this, XRCID("preview_control_point_tool"));
790  // process enter key in num transform boxes
791  Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnNumTransform, this, XRCID("input_yaw"));
792  Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnNumTransform, this, XRCID("input_pitch"));
793  Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnNumTransform, this, XRCID("input_roll"));
794  Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnNumTransform, this, XRCID("input_x"));
795  Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnNumTransform, this, XRCID("input_y"));
796  Bind(wxEVT_TEXT_ENTER, &GLPreviewFrame::OnNumTransform, this, XRCID("input_z"));
797 
798  if (cfg->Read("/GLPreviewFrame/isShown", 0l) != 0)
799  {
800 #if defined __WXMSW__ || defined __WXMAC__
801  InitPreviews();
802  Show();
803 #else
804  Show();
806 #endif
807  }
808  SetDropTarget(new PanoDropTarget(m_pano, true));
809 #if defined __WXMAC__
810  Layout();
811  Update();
812 #endif
813 }
814 
816 {
817 #ifdef __WXGTK__
818  if(loadedLayout)
819  {
820  return;
821  };
822  loadedLayout=true;
823 #endif
824  wxString OpenGLLayout=wxConfig::Get()->Read("/GLPreviewFrame/OpenGLLayout");
825  if(!OpenGLLayout.IsEmpty())
826  {
827  m_mgr->LoadPerspective(OpenGLLayout,true);
828 #ifdef __WXGTK__
829  if(!GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked())
830  {
831  wxAuiPaneInfo &inf = m_mgr->GetPane("overview");
832  if (inf.IsOk())
833  {
834  inf.Hide();
835  }
836  m_GLOverview->SetActive(false);
837  };
838  m_mgr->Update();
839  wxShowEvent dummy;
840  dummy.SetShow(true);
841  OnShowEvent(dummy);
842 #endif
843  };
844  FillBlendChoice();
845 };
846 
848 {
849  wxConfigBase * cfg = wxConfigBase::Get();
850 
851  hugin_utils::StoreFramePosition(this, "GLPreviewFrame");
852 
853  if ( (!this->IsIconized()) && (! this->IsMaximized()) && this->IsShown()) {
854  cfg->Write("/GLPreviewFrame/isShown", 1l);
855  } else {
856  cfg->Write("/GLPreviewFrame/isShown", 0l);
857  }
858 
859  cfg->Write("/GLPreviewFrame/blendMode", m_BlendModeChoice->GetSelection());
860  cfg->Write("/GLPreviewFrame/OpenGLLayout", m_mgr->SavePerspective());
861  cfg->Write("/GLPreviewFrame/overview_hidden", !(GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked()));
862  cfg->Write("/GLPreviewFrame/showPreviewGrid", GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked());
863  cfg->Write("/GLPreviewFrame/individualDragMode", individualDragging());
864  cfg->Write("/GLPreviewFrame/guide",m_GuideChoiceProj->GetSelection());
865 };
866 
868 {
869  DEBUG_TRACE("dtor writing config");
871 
872  // delete all of the tools. When the preview is never used we never get an
873  // OpenGL context and therefore don't create the tools.
874  if (crop_tool)
875  {
887  }
898  }
906  }
907  m_exposureTextCtrl->PopEventHandler(true);
908  m_HFOVText->PopEventHandler(true);
909  m_rangeCompressionTextCtrl->PopEventHandler(true);
910  m_VFOVText->PopEventHandler(true);
911  m_ROILeftTxt->PopEventHandler(true);
912  m_ROIRightTxt->PopEventHandler(true);
913  m_ROITopTxt->PopEventHandler(true);
914  m_ROIBottomTxt->PopEventHandler(true);
915  for (int i=0; i < m_ToggleButtons.size(); i++)
916  {
917  m_ToggleButtons[i]->PopEventHandler(true);
918  m_GroupToggleButtons[i]->PopEventHandler(true);
919  }
920  for (int i=0; i < PANO_PROJECTION_MAX_PARMS; i++)
921  {
922  m_projParamTextCtrl[i]->PopEventHandler(true);
923  };
924  m_pano.removeObserver(this);
925 
926  // deinitialize the frame manager
927  m_mgr->UnInit();
928  if (m_mgr) {
929  delete m_mgr;
930  }
932  {
933  delete m_filemenuSimple;
934  }
935  else
936  {
937  delete m_filemenuAdvanced;
938  };
939 
940  DEBUG_TRACE("dtor end");
941 }
942 
944 {
946  {
950  };
951 };
952 
957 {
958  if (m_BlendModeChoice != NULL)
959  {
960  int index=m_BlendModeChoice->GetSelection();
961  if(index==0)
962  {
963  // normal mode
964  if (preview_helper != NULL
965  && difference_tool != NULL)
966  {
968  };
969 
970  if (panosphere_overview_helper != NULL
971  && panosphere_difference_tool != NULL)
972  {
974  };
975 
976  if (plane_overview_helper != NULL
977  && plane_difference_tool != NULL)
978  {
980  };
981 
982 
983  }
984  else
985  {
986  if(index==m_differenceIndex)
987  {
988  // difference mode
989  if (preview_helper != NULL
990  && identify_tool != NULL
991  && difference_tool != NULL )
992  {
994 // preview_helper->DeactivateTool(identify_tool);
995  m_identify_togglebutton->SetValue(false);
998  };
999 
1000  // difference mode
1001  if (panosphere_overview_helper != NULL
1003  && panosphere_difference_tool != NULL)
1004  {
1005 // panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool);
1008  };
1009 
1010  // difference mode
1011  if (plane_overview_helper != NULL
1012  && plane_overview_identify_tool != NULL
1013  && plane_difference_tool != NULL)
1014  {
1015 // plane_overview_helper->DeactivateTool(plane_overview_identify_tool);
1018  };
1019 
1020  }
1021  else
1022  {
1023  DEBUG_WARN("Unknown blend mode selected");
1024  };
1025  }
1026  }
1027 }
1028 
1030 {
1031  m_ROILeftTxt->ChangeValue(wxString::Format("%d", opts.getROI().left() ));
1032  m_ROIRightTxt->ChangeValue(wxString::Format("%d", opts.getROI().right() ));
1033  m_ROITopTxt->ChangeValue(wxString::Format("%d", opts.getROI().top() ));
1034  m_ROIBottomTxt->ChangeValue(wxString::Format("%d", opts.getROI().bottom() ));
1035 
1036  // display the current aspect ratio
1037  if (opts.getROI().area() > 0)
1038  {
1039  const int commonDivisor = hugin_utils::gcd(opts.getROI().width(), opts.getROI().height());
1040  wxString labelAspectRatio;
1041  if (commonDivisor > std::pow(10, hugin_utils::floori(log10f(std::max(opts.getROI().width(), opts.getROI().height()))) - 2))
1042  {
1043  labelAspectRatio = wxString::Format("%d:%d", opts.getROI().width() / commonDivisor, opts.getROI().height() / commonDivisor);
1044  }
1045  else
1046  {
1047  const float ratio = 1.0f * opts.getROI().width() / opts.getROI().height();
1048  if (ratio > 1.0f)
1049  {
1050  labelAspectRatio=wxString::Format("%.2f:1", ratio);
1051  }
1052  else
1053  {
1054  labelAspectRatio=wxString::Format("1:%.2f", 1.0f / ratio);
1055  };
1056  };
1057  XRCCTRL(*this, "crop_aspect_label", wxStaticText)->SetLabel(labelAspectRatio);
1058  };
1059 
1060 };
1061 
1063 {
1064  m_alignButton->Enable(pano.getNrOfImages()>0);
1065 
1066  if(pano.getNrOfImages()==0)
1067  {
1068  m_createButton->Disable();
1069  XRCCTRL(*this, "ass_status_text", wxStaticText)->SetLabel(_("No images loaded."));
1070  }
1071  else
1072  {
1073  bool enableCreate = false;
1074  // check if images are at position 0
1075  for (size_t i = 0; i < pano.getNrOfImages(); ++i)
1076  {
1077  const HuginBase::SrcPanoImage& img = pano.getImage(i);
1078  if (img.getYaw() != 0.0 || img.getPitch() != 0.0 || img.getRoll() != 0.0)
1079  {
1080  enableCreate = true;
1081  break;
1082  };
1083  };
1084  // disable create button after loading images
1085  const std::string lastCmd = PanoCommand::GlobalCmdHist::getInstance().getLastCommandName();
1086  if (lastCmd == "add images" || lastCmd == "add and distribute images")
1087  {
1088  enableCreate = false;
1089  };
1090  if (!enableCreate && pano.getNrOfImages() == 1)
1091  {
1092  // some more checks for single image projects
1094  {
1095  enableCreate = true;
1096  };
1097  if (pano.getOptions().getROI() != vigra::Rect2D(pano.getOptions().getSize()))
1098  {
1099  enableCreate = true;
1100  };
1101  if (pano.getImage(0).getProjection() == HuginBase::SrcPanoImage::EQUIRECTANGULAR)
1102  {
1103  enableCreate = true;
1104  };
1105  };
1106  m_createButton->Enable(enableCreate);
1107  }
1108 
1109  if (pano.getNrOfImages() > 1)
1110  {
1111  // in wxWidgets 2.9, format must have types that exactly match.
1112  // However std::size_t could be any unsiged integer, so we cast it to
1113  // unsigned long.int to be on the safe side.
1114  wxString alignMsg = wxString::Format(_("%lu images are connected by %lu control points.\n"), (unsigned long int) pano.getNrOfImages(), (unsigned long int) pano.getCtrlPoints().size());
1115 
1116  if (m_pano.getNrOfCtrlPoints() > 0)
1117  {
1118  // find components..
1120  const HuginGraph::ImageGraph::Components comps = graph.GetComponents();
1121  if (comps.size() > 1)
1122  {
1123  alignMsg += wxString::Format(_("%lu unconnected image groups found: %s\n"), static_cast<unsigned long int>(comps.size()), Components2Str(comps).c_str());
1124  }
1125  else
1126  {
1127  if (m_pano.needsOptimization())
1128  {
1129  alignMsg += _("Images or control points have changed, new alignment is needed.");
1130  }
1131  else
1132  {
1133  HuginBase::CalculateCPStatisticsError calcStats(m_pano, MainFrame::Get()->GetOptimizeOnlyActiveImages(), MainFrame::Get()->GetOptimizeIgnoreLineCp());
1134  calcStats.run();
1135  const double max = calcStats.getResultMax();
1136  const double mean = calcStats.getResultMean();
1137 
1138  if (max != 0.0)
1139  {
1140  alignMsg = alignMsg + wxString::Format(_("Mean error after optimization: %.1f pixel, max: %.1f"), mean, max);
1141  }
1142  }
1143  }
1144  }
1145  wxStaticText* statusCtrl = XRCCTRL(*this, "ass_status_text", wxStaticText);
1146  statusCtrl->SetLabel(alignMsg);
1147  statusCtrl->InvalidateBestSize();
1148  m_tool_notebook->GetPage(0)->Layout();
1149  Refresh();
1150  }
1151  else
1152  {
1153  if (pano.getNrOfImages() == 1)
1154  {
1155  XRCCTRL(*this, "ass_status_text", wxStaticText)->SetLabel(_("One image loaded."));
1156  };
1157  };
1158 
1159  GetMenuBar()->Enable(XRCID("ID_EDITUNDO"), PanoCommand::GlobalCmdHist::getInstance().canUndo());
1160  GetMenuBar()->Enable(XRCID("ID_EDITREDO"), PanoCommand::GlobalCmdHist::getInstance().canRedo());
1161 
1162  // TODO: update meaningful help text and dynamic links to relevant tabs
1163 
1164  const HuginBase::PanoramaOptions & opts = pano.getOptions();
1165 
1166  wxString projection;
1167  m_ProjectionChoice->SetSelection(opts.getProjection());
1168  m_VFOVSlider->Enable( opts.fovCalcSupported(opts.getProjection()) );
1169 
1170  // No HDR display yet.
1171  /*
1172  m_outputModeChoice->SetSelection(opts.outputMode);
1173  if (opts.outputMode == PanoramaOptions::OUTPUT_HDR) {
1174  m_exposureTextCtrl->Hide();
1175  m_defaultExposureBut->Hide();
1176  m_decExposureBut->Hide();
1177  m_incExposureBut->Hide();
1178  } else {
1179  m_exposureTextCtrl->Show();
1180  m_defaultExposureBut->Show();
1181  m_decExposureBut->Show();
1182  m_incExposureBut->Show();
1183  }*/
1184  m_exposureTextCtrl->ChangeValue(wxString(hugin_utils::doubleToString(opts.outputExposureValue,2).c_str(), wxConvLocal));
1185  m_rangeCompressionTextCtrl->ChangeValue(wxString(hugin_utils::doubleToString(opts.outputRangeCompression, 1).c_str(), wxConvLocal));
1186 
1187  const bool activeImgs = !pano.getActiveImages().empty();
1188 
1189  // TODO: enable display of parameters and set their limits, if projection has some.
1190 
1191  int nParam = opts.m_projFeatures.numberOfParameters;
1192  bool relayout = false;
1193  // if the projection format has changed
1194  if (opts.getProjection() != m_oldProjFormat) {
1195  DEBUG_DEBUG("Projection format changed");
1196  if (nParam) {
1197  // show parameters and update labels.
1198  m_projection_panel->GetSizer()->Show(m_projParamSizer, true, true);
1199  int i;
1200  for (i=0; i < nParam; i++) {
1201  const pano_projection_parameter * pp = & (opts.m_projFeatures.parm[i]);
1202  wxString str2(pp->name, wxConvLocal);
1203  str2 = wxGetTranslation(str2);
1204  m_projParamNamesLabel[i]->SetLabel(str2);
1205  m_projParamSlider[i]->SetRange(hugin_utils::roundi(pp->minValue), hugin_utils::roundi(pp->maxValue));
1206  }
1207  for(;i < PANO_PROJECTION_MAX_PARMS; i++) {
1208  m_projParamNamesLabel[i]->Hide();
1209  m_projParamSlider[i]->Hide();
1210  m_projParamTextCtrl[i]->Hide();
1211  }
1212  relayout = true;
1213  } else {
1214  m_projection_panel->GetSizer()->Show(m_projParamSizer, false, true);
1215  relayout = true;
1216  }
1217  }
1218  if (nParam) {
1219  // display new values
1220  std::vector<double> params = opts.getProjectionParameters();
1221  assert((int) params.size() == nParam);
1222  for (int i=0; i < nParam; i++) {
1223  wxString val = wxString(hugin_utils::doubleToString(params[i],1).c_str(), wxConvLocal);
1224  m_projParamTextCtrl[i]->ChangeValue(wxString(val.wc_str(), wxConvLocal));
1225  m_projParamSlider[i]->SetValue(hugin_utils::roundi(params[i]));
1226  }
1227  }
1228  if (relayout) {
1229  m_projection_panel->Layout();
1230  Refresh();
1231  }
1232  SetStatusText(wxString::Format("%.1f x %.1f", opts.getHFOV(), opts.getVFOV()),2);
1233  m_HFOVSlider->SetValue(hugin_utils::roundi(opts.getHFOV()));
1234  m_VFOVSlider->SetValue(hugin_utils::roundi(opts.getVFOV()));
1235  std::string val;
1236  val = hugin_utils::doubleToString(opts.getHFOV(),1);
1237  m_HFOVText->ChangeValue(wxString(val.c_str(), wxConvLocal));
1238  val = hugin_utils::doubleToString(opts.getVFOV(),1);
1239  m_VFOVText->ChangeValue(wxString(val.c_str(), wxConvLocal));
1240  m_VFOVText->Enable(opts.fovCalcSupported(opts.getProjection()));
1241 
1242  m_oldProjFormat = opts.getProjection();
1243 
1244  XRCCTRL(*this,"preview_autocrop_tool",wxButton)->Enable(activeImgs);
1245  XRCCTRL(*this,"preview_stack_autocrop_tool",wxButton)->Enable(activeImgs);
1246  UpdateRoiDisplay(opts);
1247 
1249  {
1251  };
1252  redrawPreview();
1253 }
1254 
1256 {
1257  DEBUG_TRACE("");
1258 
1259  bool dirty = false;
1260 
1261  unsigned int nrImages = pano.getNrOfImages();
1262  unsigned int nrButtons = m_ToggleButtons.size();
1263 
1264  GetMenuBar()->Enable(XRCID("action_optimize"), nrImages > 0);
1265 
1266 // m_displayedImgs.clear();
1267 
1268  // remove items for nonexisting images
1269  for (int i=nrButtons-1; i>=(int)nrImages; i--)
1270  {
1271  m_ButtonSizer->Detach(m_ToggleButtonPanel[i]);
1272  // Image toggle buttons have a event handler on the stack which
1273  // must be removed before the buttons get destroyed.
1274  m_ToggleButtons[i]->PopEventHandler();
1275  m_GroupToggleButtons[i]->PopEventHandler();
1276  delete m_ToggleButtons[i];
1277  delete m_GroupToggleButtons[i];
1278  delete m_ToggleButtonPanel[i];
1279  m_ToggleButtons.pop_back();
1280  m_GroupToggleButtons.pop_back();
1281  m_ToggleButtonPanel.pop_back();
1282  delete toogle_button_event_handlers[i];
1283  toogle_button_event_handlers.pop_back();
1286  dirty = true;
1287  }
1288 
1289  //change overview mode to panosphere if the translation plane parameter are non zero
1291  {
1293  {
1295  m_OverviewModeChoice->SetSelection(0);
1296  //check if drag mode is mosaic, if so reset to normal
1297  if(drag_tool)
1298  {
1300  {
1301  m_DragModeChoice->SetSelection(m_DragModeChoice->GetSelection()-2);
1304  // adjust the layout
1305  DragChoiceLayout(m_DragModeChoice->GetSelection());
1306  };
1307  };
1308  }
1309  }
1310 
1311  // add buttons
1312  if ( nrImages >= nrButtons ) {
1313  for(HuginBase::UIntSet::const_iterator it = changed.begin(); it != changed.end(); ++it){
1314  if (*it >= nrButtons) {
1315  // create new item.
1316 // wxImage * bmp = new wxImage(sz.GetWidth(), sz.GetHeight());
1317  //put wxToggleButton in a wxPanel because
1318  //on Windows the background colour of wxToggleButton can't be changed
1319  wxPanel *pan = new wxPanel(m_ButtonPanel);
1320  wxBoxSizer * siz = new wxBoxSizer(wxVERTICAL);
1321  pan->SetSizer(siz);
1322  wxToggleButton * but = new wxToggleButton(pan,
1323  ID_TOGGLE_BUT + *it,
1324  wxString::Format(" %d ",*it),
1325  wxDefaultPosition, wxDefaultSize,
1326  wxBU_EXACTFIT);
1327  but->Bind(wxEVT_CONTEXT_MENU, &GLPreviewFrame::OnImageContextMenu, this);
1328 
1329  wxCheckBox *butcheck = new wxCheckBox(pan, wxID_ANY, wxEmptyString);
1330 
1331 #if defined __WXMSW__ || defined __WXMAC__
1332  //we need a border around the button to see the colored panel
1333  //because changing backgroundcolor of wxToggleButton does not work in wxMSW
1334  siz->AddSpacer(5);
1335  siz->Add(butcheck, 0, wxALIGN_CENTRE_HORIZONTAL | wxFIXED_MINSIZE, 0);
1336  siz->Add(but,0,wxLEFT | wxRIGHT | wxBOTTOM , 5);
1337 #else
1338  siz->Add(but,0,wxALL ,0);
1339  siz->Add(butcheck, 0, wxALL | wxFIXED_MINSIZE, 0);
1340 #endif
1341  // for the identification tool to work, we need to find when the
1342  // mouse enters and exits the button. We use a custom event
1343  // handler, which will also toggle the images:
1345  event_handler->AddIdentifyTool(&identify_tool);
1348  toogle_button_event_handlers.push_back(event_handler);
1349  but->PushEventHandler(event_handler);
1350 
1351  ImageGroupButtonEventHandler * group_event_handler = new
1352  ImageGroupButtonEventHandler(*it, this, &m_pano);
1353  group_event_handler->AddDragTool((DragTool**) &drag_tool);
1354  group_event_handler->AddDragTool((DragTool**) &overview_drag_tool);
1355  group_event_handler->AddIdentifyTool(&identify_tool);
1356  group_event_handler->AddIdentifyTool(&panosphere_overview_identify_tool);
1357  group_event_handler->AddIdentifyTool(&plane_overview_identify_tool);
1358  toggle_group_button_event_handlers.push_back(group_event_handler);
1359  butcheck->PushEventHandler(group_event_handler);
1360  butcheck->Show(individualDragging() && m_mode==mode_drag);
1361 
1362  but->SetValue(true);
1363  m_ButtonSizer->Add(pan,
1364  0,
1365  wxLEFT | wxTOP,
1366  0);
1367  m_ToggleButtons.push_back(but);
1368  m_GroupToggleButtons.push_back(butcheck);
1369  m_ToggleButtonPanel.push_back(pan);
1370  dirty = true;
1371  }
1372  }
1373  }
1374 
1375  // update existing items
1376  HuginBase::UIntSet displayedImages = m_pano.getActiveImages();
1377  for (unsigned i=0; i < nrImages; i++) {
1378  m_ToggleButtons[i]->SetValue(set_contains(displayedImages, i));
1379  wxFileName tFilename(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
1380  m_ToggleButtons[i]->SetToolTip(tFilename.GetFullName());
1381  }
1382 
1383  if (dirty) {
1384  m_ButtonSizer->FitInside(m_ButtonPanel);
1385  Layout();
1386  SendSizeEvent();
1387  DEBUG_INFO("New m_ButtonPanel width: " << (m_ButtonPanel->GetSize()).GetWidth());
1388  DEBUG_INFO("New m_ButtonPanel Height: " << (m_ButtonPanel->GetSize()).GetHeight());
1389  }
1390  if(nrImages==0)
1391  {
1393  m_tool_notebook->ChangeSelection(mode_assistant);
1394  };
1395  for(size_t i=2; i<m_tool_notebook->GetPageCount();i++)
1396  {
1397  m_tool_notebook->GetPage(i)->Enable(nrImages!=0);
1398  };
1399  redrawPreview();
1400 }
1401 
1403 {
1404  m_GLPreview->Refresh();
1405  m_GLOverview->Refresh();
1406 }
1407 
1409 {
1410  if (preview_helper)
1411  {
1413  m_GLPreview->Redraw();
1414  };
1415 }
1416 
1417 void GLPreviewFrame::OnShowEvent(wxShowEvent& e)
1418 {
1419 
1420  DEBUG_TRACE("OnShow");
1421  bool toggle_on = GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked();
1422  wxAuiPaneInfo &inf = m_mgr->GetPane("overview");
1423  if (inf.IsOk()) {
1424  if (e.IsShown()) {
1425  if (!inf.IsShown() && toggle_on ) {
1426  inf.Show();
1427  m_mgr->Update();
1428  }
1429  } else {
1430  if (inf.IsFloating() && inf.IsShown()) {
1431  DEBUG_DEBUG("hiding overview float");
1432  inf.Hide();
1433  m_mgr->Update();
1434  }
1435  }
1436  }
1437 
1438 }
1439 
1440 //the following methods are to substitude the GLViewer KeyUp and KeyDown methods
1441 //so that tools use key events that happen globally to the preview frame
1442 //however only key up event is sent, and not key down
1443 //so until this is resolved they will remain to be handled by GLViewer
1444 void GLPreviewFrame::KeyDown(wxKeyEvent& e)
1445 {
1446  if (preview_helper) {
1447  preview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
1448  }
1449  if (GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked()) {
1451  if (plane_overview_helper) {
1452  plane_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
1453  }
1456  panosphere_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
1457  }
1458  }
1459 
1460  }
1461  e.Skip();
1462 }
1463 
1464 void GLPreviewFrame::KeyUp(wxKeyEvent& e)
1465 {
1466  if (preview_helper) {
1467  preview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
1468  }
1469  if (GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked()) {
1471  if (plane_overview_helper) {
1472  plane_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
1473  }
1474  }
1477  panosphere_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
1478  }
1479  }
1480 
1481  }
1482  e.Skip();
1483 }
1484 
1485 
1486 
1487 void GLPreviewFrame::OnOverviewToggle(wxCommandEvent& e)
1488 {
1489  DEBUG_TRACE("overview toggle");
1490  bool toggle_on = GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked();
1491  wxAuiPaneInfo &inf = m_mgr->GetPane("overview");
1492  if (inf.IsOk()) {
1493  if (inf.IsShown() && !toggle_on) {
1494  inf.Hide();
1495  m_GLOverview->SetActive(false);
1496  m_mgr->Update();
1497  } else if (!(inf.IsShown() && toggle_on)) {
1498  inf.Show();
1499 #if defined __WXMSW__ || defined __WXMAC__
1500  m_GLOverview->SetActive(true);
1501  m_mgr->Update();
1502 #else
1503  m_mgr->Update();
1504  m_GLOverview->SetActive(true);
1505 #endif
1506  }
1507  }
1508 }
1509 
1510 void GLPreviewFrame::OnSwitchPreviewGrid(wxCommandEvent & e)
1511 {
1512  if(GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked())
1513  {
1516  }
1517  else
1518  {
1521  }
1522  m_GLPreview->Refresh();
1523  m_GLOverview->Refresh();
1524 }
1525 
1526 void GLPreviewFrame::OnClose(wxCloseEvent& event)
1527 {
1528  DEBUG_TRACE("OnClose")
1529  // do not close, just hide if we're not forced
1530  if(m_guiLevel==GUI_SIMPLE)
1531  {
1532  if(!MainFrame::Get()->CloseProject(event.CanVeto(), MainFrame::CLOSE_PROGRAM))
1533  {
1534  if (event.CanVeto())
1535  {
1536  event.Veto();
1537  return;
1538  };
1539  };
1540  MainFrame::Get()->Close(true);
1541  }
1542  else
1543  {
1544  if (event.CanVeto())
1545  {
1546  event.Veto();
1547  Hide();
1548  DEBUG_DEBUG("hiding");
1549  }
1550  else
1551  {
1552  DEBUG_DEBUG("closing");
1553  this->Destroy();
1554  }
1555  };
1556 }
1557 
1558 #if 0
1559 // need to add the wxChoice somewhere
1560 void PreviewFrame::OnProjectionChanged()
1561 {
1562  PanoramaOptions opt = m_pano.getOptions();
1563  int lt = m_ProjectionChoice->GetSelection();
1564  wxString Ip;
1565  switch ( lt ) {
1566  case PanoramaOptions::RECTILINEAR: Ip = _("Rectilinear"); break;
1567  case PanoramaOptions::CYLINDRICAL: Ip = _("Cylindrical"); break;
1568  case PanoramaOptions::EQUIRECTANGULAR: Ip = _("Equirectangular"); break;
1569  }
1570  opt.projectionFormat = (PanoramaOptions::ProjectionFormat) lt;
1572  new PanoCommand::SetPanoOptionsCmd( pano, opt )
1573  );
1574  DEBUG_DEBUG ("Projection changed: " << lt << ":" << Ip )
1575 
1576 
1577 }
1578 #endif
1579 
1581 {
1582  if (m_pano.getActiveImages().empty()) return;
1583 
1584  // reset zoom so that full pano is visible
1585  ResetPreviewZoom();
1588  );
1589 }
1590 
1591 void GLPreviewFrame::OnStraighten(wxCommandEvent & e)
1592 {
1593  if (m_pano.getNrOfImages() == 0) return;
1594 
1597  );
1598 }
1599 
1600 void GLPreviewFrame::OnFitPano(wxCommandEvent & e)
1601 {
1602  if (m_pano.getActiveImages().empty()) return;
1603 
1604  DEBUG_TRACE("");
1607  fitPano.run();
1608  opt.setHFOV(fitPano.getResultHorizontalFOV());
1610 
1611  // reset zoom so that full pano is visible
1612  ResetPreviewZoom();
1613 
1616  );
1617 
1618  DEBUG_INFO ( "new fov: [" << opt.getHFOV() << " "<< opt.getVFOV() << "] => height: " << opt.getHeight() );
1619 }
1620 
1621 void GLPreviewFrame::OnShowAll(wxCommandEvent & e)
1622 {
1623  if (m_pano.getNrOfImages() == 0) return;
1624 
1625  HuginBase::UIntSet displayedImgs;
1627  {
1628  fill_set(displayedImgs, 0, m_pano.getNrOfImages() - 1);
1629  }
1630  else
1631  {
1633  {
1634  displayedImgs = m_pano.getActiveImages();
1635  };
1636  std::vector<HuginBase::UIntVector> stackedImg = HuginBase::getSortedStacks(&m_pano);
1637  for (size_t i = 0; i < stackedImg.size(); ++i)
1638  {
1639  switch (m_selectAllMode)
1640  {
1642  displayedImgs.insert(*(stackedImg[i].rbegin()));
1643  break;
1644  case SELECT_DARKEST_IMAGES:
1645  displayedImgs.insert(*(stackedImg[i].begin()));
1646  break;
1647  case SELECT_MEDIAN_IMAGES:
1648  default:
1649  displayedImgs.insert(stackedImg[i][stackedImg[i].size() / 2]);
1650  break;
1651  };
1652  };
1653  };
1655  new PanoCommand::SetActiveImagesCmd(m_pano, displayedImgs)
1656  );
1657 }
1658 
1659 void GLPreviewFrame::OnShowNone(wxCommandEvent & e)
1660 {
1661  if (m_pano.getNrOfImages() == 0) return;
1662 
1664  for (unsigned int i=0; i < m_pano.getNrOfImages(); i++) {
1665  m_ToggleButtons[i]->SetValue(false);
1666  }
1667  HuginBase::UIntSet displayedImgs;
1669  new PanoCommand::SetActiveImagesCmd(m_pano, displayedImgs)
1670  );
1671 }
1672 
1673 void GLPreviewFrame::OnNumTransform(wxCommandEvent & e)
1674 {
1675  if (m_pano.getNrOfImages() == 0) return;
1676 
1677  wxString text;
1678  double y;
1679  double p;
1680  double r;
1681  double x;
1682  double z;
1683 
1684  int index = m_DragModeChoice->GetSelection();
1685  switch (index) {
1686  case 0: //normal
1687  case 1: //normal, individual
1688  //@TODO limit numeric transform to selected images
1689  text = XRCCTRL(*this,"input_yaw",wxTextCtrl)->GetValue();
1690  if(!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), y))
1691  {
1692  wxBell();
1693  hugin_utils::HuginMessageBox(_("Yaw value must be numeric."), _("Hugin"), wxOK | wxICON_ERROR, this);
1694  return;
1695  }
1696  text = XRCCTRL(*this,"input_pitch",wxTextCtrl)->GetValue();
1697  if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), p))
1698  {
1699  wxBell();
1700  hugin_utils::HuginMessageBox(_("Pitch value must be numeric."), _("Hugin"), wxOK | wxICON_ERROR, this);
1701  return;
1702  }
1703  text = XRCCTRL(*this,"input_roll",wxTextCtrl)->GetValue();
1704  if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), r))
1705  {
1706  wxBell();
1707  hugin_utils::HuginMessageBox(_("Roll value must be numeric."), _("Hugin"), wxOK | wxICON_ERROR, this);
1708  return;
1709  }
1711  new PanoCommand::RotatePanoCmd(m_pano, y, p, r)
1712  );
1713  break;
1714  case 2: //mosaic
1715  case 3: //mosaic, individual
1716  //@TODO limit numeric transform to selected images
1717  text = XRCCTRL(*this,"input_x",wxTextCtrl)->GetValue();
1718  if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), x))
1719  {
1720  wxBell();
1721  hugin_utils::HuginMessageBox(_("X value must be numeric."), _("Hugin"), wxOK | wxICON_ERROR, this);
1722  return;
1723  }
1724  text = XRCCTRL(*this,"input_y",wxTextCtrl)->GetValue();
1725  if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), y))
1726  {
1727  wxBell();
1728  hugin_utils::HuginMessageBox(_("Y value must be numeric."), _("Hugin"), wxOK | wxICON_ERROR, this);
1729  return;
1730  }
1731  text = XRCCTRL(*this,"input_z",wxTextCtrl)->GetValue();
1732  if(!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), z))
1733  {
1734  wxBell();
1735  hugin_utils::HuginMessageBox(_("Z value must be numeric."), _("Hugin"), wxOK | wxICON_ERROR, this);
1736  return;
1737  }
1740  );
1741  break;
1742  }
1743 }
1744 
1745 void GLPreviewFrame::OnExposureChanged(wxCommandEvent & e)
1746 {
1748  // exposure
1749  wxString text = m_exposureTextCtrl->GetValue();
1750  DEBUG_INFO ("target exposure = " << text.mb_str(wxConvLocal) );
1751  double p = 0;
1752  if (text != wxEmptyString) {
1753  if (!hugin_utils::str2double(text, p)) {
1754  wxLogError(_("Value must be numeric."));
1755  return;
1756  }
1757  }
1758  opts.outputExposureValue = p;
1761  );
1762 }
1763 
1765 {
1770  );
1771 }
1772 
1774 {
1779  );
1780 }
1781 
1783 {
1785  // range compression
1786  const wxString text = m_rangeCompressionTextCtrl->GetValue();
1787  if (!text.IsEmpty())
1788  {
1789  double p = 0;
1790  if (!hugin_utils::str2double(text, p))
1791  {
1792  wxLogError(_("Value must be numeric."));
1793  return;
1794  };
1795  if (p < 0 || p>20)
1796  {
1797  wxLogError(_("Value for range compression is outside of valid range."));
1798  return;
1799  };
1800  if (p != opts.outputRangeCompression)
1801  {
1802  opts.outputRangeCompression = p;
1805  );
1806  };
1807  };
1808 }
1809 
1810 
1812 {
1814  int nParam = opts.m_projFeatures.numberOfParameters;
1815  std::vector<double> para = opts.getProjectionParameters();
1816  for (int i = 0; i < nParam; i++) {
1817  if (e.GetEventObject() == m_projParamTextCtrl[i]) {
1818  wxString text = m_projParamTextCtrl[i]->GetValue();
1819  DEBUG_INFO ("param " << i << ": = " << text.mb_str(wxConvLocal) );
1820  double p = 0;
1821  if (text != wxEmptyString) {
1822  if (!hugin_utils::str2double(text, p)) {
1823  wxLogError(_("Value must be numeric."));
1824  return;
1825  }
1826  }
1827  para[i] = p;
1828  }
1829  }
1830  opts.setProjectionParameters(para);
1833  );
1834 }
1835 
1837 {
1842  );
1843 };
1844 
1846 {
1848  const int nParam = opt.m_projFeatures.numberOfParameters;
1849  std::vector<double> para = opt.getProjectionParameters();
1850  for (int i = 0; i < nParam; i++)
1851  {
1852  if (e.GetEventObject() == m_projParamSlider[i])
1853  {
1854  // update
1855  para[i] = e.GetInt();
1856  break;
1857  }
1858  }
1859  opt.setProjectionParameters(para);
1860  opt.setHFOV(m_HFOVSlider->GetValue());
1861  opt.setVFOV(m_VFOVSlider->GetValue());
1863 }
1864 
1866 {
1868  const int nParam = opt.m_projFeatures.numberOfParameters;
1869  std::vector<double> para = opt.getProjectionParameters();
1870  for (int i = 0; i < nParam; i++)
1871  {
1872  if (e.GetEventObject() == m_projParamSlider[i])
1873  {
1874  // update
1875  para[i] = e.GetInt();
1876  m_projParamTextCtrl[i]->ChangeValue(wxString::Format("%d", e.GetInt()));
1877  break;
1878  }
1879  }
1880  opt.setProjectionParameters(para);
1881  // we only actually update the panorama fully when the mouse is released.
1882  // As we are dragging it we don't want to create undo events, but we would
1883  // like to update the display, so we change the GLViewer's ViewState and
1884  // request a redraw.
1886  m_GLPreview->Refresh();
1887 }
1888 
1889 void GLPreviewFrame::OnBlendChoice(wxCommandEvent & e)
1890 {
1891  if (e.GetEventObject() == m_BlendModeChoice)
1892  {
1893  updateBlendMode();
1894  }
1895  else
1896  {
1897  // FIXME DEBUG_WARN("wxChoice event from unknown object received");
1898  }
1899 }
1900 
1901 void GLPreviewFrame::OnDragChoice(wxCommandEvent & e)
1902 {
1903  if (drag_tool)
1904  {
1906  int index = m_DragModeChoice->GetSelection();
1907  switch (index) {
1908  case 0: //normal
1909  case 1:
1910  newDragMode=DragTool::drag_mode_normal;
1911  break;
1912  case 2: //mosaic
1913  case 3:
1914  newDragMode=DragTool::drag_mode_mosaic;
1915  break;
1916  }
1917  if(newDragMode==DragTool::drag_mode_mosaic)
1918  {
1920  {
1921  if (hugin_utils::HuginMessageBox(_("The mosaic/plane mode works only correct for a remapping plane of yaw=0 and pitch=0.\nBut your project has non-zero Tpy and Tpp parameters.\nShould the Tpy and Tpp parameters reset to zero?"),
1922  _("Hugin"), wxYES_NO | wxICON_QUESTION, this) == wxYES)
1923  {
1925  }
1926  else
1927  {
1928  m_DragModeChoice->SetSelection(index-2);
1929  return;
1930  };
1931  };
1932  //switch overview mode to plane
1933  UpdateOverviewMode(1);
1934  m_OverviewModeChoice->SetSelection(1);
1935  }
1936  else
1937  {
1938  //new mode is normal
1939  //set overview back to panosphere mode
1940  UpdateOverviewMode(0);
1941  m_OverviewModeChoice->SetSelection(0);
1944  };
1945  //update drag mode
1946  drag_tool->setDragMode(newDragMode);
1948  // adjust the layout
1949  DragChoiceLayout(index);
1950  };
1951 };
1952 
1954 {
1955  size_t nr = m_pano.getNrOfImages();
1956  for (size_t i = 0 ; i < nr; i++)
1957  {
1958  if (m_pano.getSrcImage(i).getTranslationPlaneYaw() != 0 ||
1959  m_pano.getSrcImage(i).getTranslationPlanePitch() != 0)
1960  {
1961  return true;
1962  };
1963  }
1964  return false;
1965 };
1966 
1968 {
1969  HuginBase::UIntSet imgs;
1971  size_t nr = newPan.getNrOfImages();
1972  for (size_t i = 0 ; i < nr ; i++)
1973  {
1974  HuginBase::SrcPanoImage img = newPan.getSrcImage(i);
1975  img.setTranslationPlaneYaw(0);
1976  img.setTranslationPlanePitch(0);
1977  newPan.setSrcImage(i,img);
1978  imgs.insert(i);
1979  }
1982  );
1983 };
1984 
1986 {
1988  if (newMode == 1)
1989  {
1990  newOverviewMode = GLOverview::PANOSPHERE_INSIDE;
1991  }
1992  else
1993  {
1994  if (newMode == 2)
1995  {
1996  newOverviewMode = GLOverview::PLANE;
1997  };
1998  };
1999  if(m_GLOverview->GetMode()==newOverviewMode)
2000  {
2001  return true;
2002  };
2003  if (newOverviewMode == GLOverview::PLANE)
2004  {
2006  {
2008  return true;
2009  }
2010  else
2011  {
2012  if (hugin_utils::HuginMessageBox(_("The mosaic/plane mode works only correct for a remapping plane of yaw=0 and pitch=0.\nBut your project has non-zero Tpy and Tpp parameters.\nShould the Tpy and Tpp parameters reset to zero?"),
2013  _("Hugin"), wxYES_NO | wxICON_QUESTION, this) == wxYES)
2014  {
2017  return true;
2018  }
2019  else
2020  {
2021  return false;
2022  };
2023  };
2024  }
2025  else
2026  {
2027  m_GLOverview->SetMode(newOverviewMode);
2028  return true;
2029  }
2030 };
2031 
2032 void GLPreviewFrame::OnOverviewModeChoice( wxCommandEvent & e)
2033 {
2034  if(UpdateOverviewMode(m_OverviewModeChoice->GetSelection()))
2035  {
2038  //set drag mode to normal if new mode is panosphere mode
2040  {
2041  m_DragModeChoice->SetSelection(m_DragModeChoice->GetSelection()-2);
2042  OnDragChoice(e);
2043  };
2044  }
2045  else
2046  {
2047  //change mode was not successful or canceled by user, set mode choice back
2048  switch (m_GLOverview->GetMode())
2049  {
2051  m_OverviewModeChoice->SetSelection(0);
2052  break;
2054  m_OverviewModeChoice->SetSelection(1);
2055  break;
2056  case GLOverview::PLANE:
2057  m_OverviewModeChoice->SetSelection(2);
2058  break;
2059  };
2060  };
2061 };
2062 
2064 {
2065  // visibility of controls based on selected drag mode
2066  bool normalMode=index==0 || index==1;
2067  XRCCTRL(*this,"label_yaw",wxStaticText)->Show(normalMode);
2068  XRCCTRL(*this,"input_yaw",wxTextCtrl)->Show(normalMode);
2069  XRCCTRL(*this,"label_pitch",wxStaticText)->Show(normalMode);
2070  XRCCTRL(*this,"input_pitch",wxTextCtrl)->Show(normalMode);
2071  XRCCTRL(*this,"label_roll",wxStaticText)->Show(normalMode);
2072  XRCCTRL(*this,"input_roll",wxTextCtrl)->Show(normalMode);
2073  XRCCTRL(*this,"label_x",wxStaticText)->Show(!normalMode);
2074  XRCCTRL(*this,"input_x",wxTextCtrl)->Show(!normalMode);
2075  XRCCTRL(*this,"label_y",wxStaticText)->Show(!normalMode);
2076  XRCCTRL(*this,"input_y",wxTextCtrl)->Show(!normalMode);
2077  XRCCTRL(*this,"label_z",wxStaticText)->Show(!normalMode);
2078  XRCCTRL(*this,"input_z",wxTextCtrl)->Show(!normalMode);
2079  // redraw layout to compress empty space
2080  XRCCTRL(*this,"apply_num_transform",wxButton)->GetParent()->Layout();
2081 }
2082 
2083 void GLPreviewFrame::OnDefaultExposure( wxCommandEvent & e )
2084 {
2085  if (m_pano.getActiveImages().size() > 0) {
2090  );
2091  }
2092 }
2093 
2094 void GLPreviewFrame::OnIncreaseExposure( wxSpinEvent & e )
2095 {
2097  opt.outputExposureValue = opt.outputExposureValue + 1.0/3;
2100  );
2101 }
2102 
2103 void GLPreviewFrame::OnDecreaseExposure( wxSpinEvent & e )
2104 {
2106  opt.outputExposureValue = opt.outputExposureValue - 1.0/3;
2109  );
2110 }
2111 
2112 void GLPreviewFrame::OnProjectionChoice( wxCommandEvent & e )
2113 {
2114  if (e.GetEventObject() == m_ProjectionChoice) {
2116  int lt = m_ProjectionChoice->GetSelection();
2117  wxString Ip;
2121  );
2122  DEBUG_DEBUG ("Projection changed: " << lt);
2123  m_projection_panel->Layout();
2124  Refresh();
2125  } else {
2126  // FIXME DEBUG_WARN("wxChoice event from unknown object received");
2127  }
2128 }
2129 
2130 /* We don't have an OpenGL hdr display yet
2131 void GLPreviewFrame::OnOutputChoice( wxCommandEvent & e)
2132 {
2133  if (e.GetEventObject() == m_outputModeChoice) {
2134  PanoramaOptions opt = m_pano.getOptions();
2135  int lt = m_outputModeChoice->GetSelection();
2136  wxString Ip;
2137  opt.outputMode = ( (PanoramaOptions::OutputMode) lt );
2138  PanoCommand::GlobalCmdHist::getInstance().addCommand(
2139  new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2140  );
2141 
2142  } else {
2143  // FIXME DEBUG_WARN("wxChoice event from unknown object received");
2144  }
2145 }
2146 */
2147 
2148 void GLPreviewFrame::SetStatusMessage(wxString message)
2149 {
2150  SetStatusText(message, 0);
2151 }
2152 
2153 void GLPreviewFrame::OnPhotometric(wxCommandEvent & e)
2154 {
2155  m_GLPreview->SetPhotometricCorrect(e.IsChecked());
2156 }
2157 
2159 {
2160  // create the tool objects.
2161  // we delay this until we have an OpenGL context so that they are free to
2162  // create texture objects and display lists before they are used.
2163  preview_helper = preview_helper_in;
2168  // bind corresponding menu events
2169  Bind(wxEVT_MENU, &GLPreviewFrame::OnCreateCP, this, ID_CREATE_CP);
2170  Bind(wxEVT_MENU, &GLPreviewFrame::OnRemoveCP, this, ID_REMOVE_CP);
2179 
2181  if(GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked())
2182  {
2184  };
2187 
2188  // activate tools that are always active.
2190  // update the blend mode which activates some tools
2191  updateBlendMode();
2193  // update toolbar
2195 }
2196 
2198 {
2199  panosphere_overview_helper = panosphere_overview_helper_in;
2205 
2208 
2210  if(GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked())
2211  {
2213  }
2214 
2215 
2219 
2222 
2223 
2224 
2225 }
2226 
2228 {
2229  plane_overview_helper = plane_overview_helper_in;
2232 
2236 
2239 
2242 
2243 }
2244 
2245 void GLPreviewFrame::OnIdentify(wxCommandEvent & e)
2246 {
2247  SetStatusText(wxEmptyString, 0); // blank status text as it refers to an old tool.
2248  if (e.IsChecked())
2249  {
2250  m_BlendModeChoice->SetSelection(0);
2257 // TurnOffTools(preview_helper->ActivateTool(identify_tool));
2258 // TurnOffTools(panosphere_overview_helper->ActivateTool(panosphere_overview_identify_tool));
2259 // TurnOffTools(plane_overview_helper->ActivateTool(plane_overview_identify_tool));
2260  } else {
2261  identify_tool->setConstantOn(false);
2264 // preview_helper->DeactivateTool(identify_tool);
2265 // panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool);
2266 // plane_overview_helper->DeactivateTool(plane_overview_identify_tool);
2268  }
2269  m_GLPreview->Refresh();
2270  m_GLOverview->Refresh();
2271 }
2272 
2273 void GLPreviewFrame::OnControlPoint(wxCommandEvent & e)
2274 {
2275  if (!m_editCP_togglebutton->GetValue())
2276  {
2277  //process event only if edit cp tool is disabled
2278  SetStatusText(wxEmptyString, 0); // blank status text as it refers to an old tool.
2279  if (e.IsChecked())
2280  {
2284  }
2285  else {
2289  }
2290  m_GLPreview->Refresh();
2291  m_GLOverview->Refresh();
2292  };
2293 }
2294 
2295 void GLPreviewFrame::TurnOffTools(std::set<Tool*> tools)
2296 {
2297  std::set<Tool*>::iterator i;
2298  for (i = tools.begin(); i != tools.end(); ++i)
2299  {
2300  if (*i == crop_tool)
2301  {
2302  // cover up the guidelines
2303  m_GLPreview->Refresh();
2304  } else if (*i == drag_tool)
2305  {
2306  // cover up its boxes
2307  m_GLPreview->Refresh();
2308  } else if (*i == identify_tool)
2309  {
2310  // disabled the identify tool, toggle its button off.
2311  m_identify_togglebutton->SetValue(false);
2312  // cover up its indicators and restore normal button colours.
2313  m_GLPreview->Refresh();
2314  m_GLOverview->Refresh();
2316  } else if (*i == preview_control_point_tool)
2317  {
2318  // disabled the control point tool.
2319  XRCCTRL(*this,"preview_control_point_tool",wxCheckBox)->SetValue(false);
2320  // cover up the control point lines.
2321  m_GLPreview->Refresh();
2322  m_GLOverview->Refresh();
2323  }
2324  }
2325 }
2326 
2327 void GLPreviewFrame::SetImageButtonColour(unsigned int image_nr,
2328  unsigned char red,
2329  unsigned char green,
2330  unsigned char blue)
2331 {
2332  // 0, 0, 0 indicates we want to go back to the system colour.
2333  // TODO: Maybe we should test this better on different themes.
2334 #if defined __WXMSW__ || defined __WXMAC__
2335  if (red || green || blue)
2336  {
2337  // the identify tool wants us to highlight an image button in the given
2338  // colour, to match up with the display in the preview.
2339  // on windows change the color of the surhugin_utils::rounding wxPanel
2340  m_ToggleButtonPanel[image_nr]->SetBackgroundColour(wxColour(red, green, blue));
2341  }
2342  else
2343  {
2344  // return to the normal colour
2345  m_ToggleButtonPanel[image_nr]->SetBackgroundColour(m_ToggleButtonPanel[image_nr]->GetParent()->GetBackgroundColour());
2346  }
2347  m_ToggleButtonPanel[image_nr]->Refresh();
2348 #else
2349  if (red || green || blue)
2350  {
2351  // change the color of the wxToggleButton
2352  m_ToggleButtons[image_nr]->SetBackgroundStyle(wxBG_STYLE_COLOUR);
2353  m_ToggleButtons[image_nr]->SetBackgroundColour(wxColour(red, green, blue));
2354  // black should be visible on the button's vibrant colours.
2355  m_ToggleButtons[image_nr]->SetForegroundColour(wxColour(0, 0, 0));
2356  }
2357  else
2358  {
2359  // return to the normal colour
2360  m_ToggleButtons[image_nr]->SetBackgroundStyle(wxBG_STYLE_SYSTEM);
2361  m_ToggleButtons[image_nr]->SetBackgroundColour(wxNullColour);
2362  m_ToggleButtons[image_nr]->SetForegroundColour(wxNullColour);
2363  };
2364  m_ToggleButtons[image_nr]->Refresh();
2365 #endif
2366 }
2367 
2369 {
2370  // when we turn off the identification tool, any buttons that were coloured
2371  // to match the image in the preview should be given back the system themed
2372  // colours.
2373  unsigned int nr_images = m_pano.getNrOfImages();
2374  for (unsigned image = 0; image < nr_images; image++)
2375  {
2376 #if defined __WXMSW__ || defined __WXMAC__
2377  m_ToggleButtonPanel[image]->SetBackgroundColour(m_ToggleButtonPanel[image]->GetParent()->GetBackgroundColour());
2378  m_ToggleButtonPanel[image]->Refresh();
2379 #else
2380  m_ToggleButtons[image]->SetBackgroundStyle(wxBG_STYLE_SYSTEM);
2381  m_ToggleButtons[image]->SetBackgroundColour(wxNullColour);
2382  m_ToggleButtons[image]->SetForegroundColour(wxNullColour);
2383  m_ToggleButtons[image]->Refresh();
2384 #endif
2385  }
2386 }
2387 
2388 void GLPreviewFrame::OnColorPicker(wxCommandEvent &e)
2389 {
2390  // blank status text as it refers to an old tool.
2391  SetStatusText(wxEmptyString, 0);
2392  if (e.IsChecked())
2393  {
2394  if (!XRCCTRL(*this, "preview_control_point_tool", wxCheckBox)->GetValue())
2395  {
2397  };
2398  // deactivate delete cp tool if active
2400  m_editCP_togglebutton->SetValue(false);
2402  }
2403  else
2404  {
2406  };
2407  m_GLPreview->Refresh();
2408 };
2409 
2410 void GLPreviewFrame::UpdateGlobalWhiteBalance(double redFactor, double blueFactor)
2411 {
2413  new PanoCommand::UpdateWhiteBalance(m_pano, redFactor, blueFactor)
2414  );
2415  //now toggle button and deactivate tool
2416  m_colorpicker_togglebutton->SetValue(false);
2417  //direct deactivation of tool does not work because this function is called by the tool itself
2418  //so we are send an event to deactivate the tool
2419  wxCommandEvent e(wxEVT_TOGGLEBUTTON);
2420  e.SetInt(0);
2421  m_colorpicker_togglebutton->GetEventHandler()->AddPendingEvent(e);
2422 };
2423 
2424 void GLPreviewFrame::OnEditCPTool(wxCommandEvent &e)
2425 {
2426  // blank status text as it refers to an old tool.
2427  SetStatusText(wxEmptyString, 0);
2428  if (e.IsChecked())
2429  {
2430  // deactivate color picker tool
2432  m_colorpicker_togglebutton->SetValue(false);
2433  // show automatically all cp
2436  }
2437  else
2438  {
2439  if (!XRCCTRL(*this, "preview_control_point_tool", wxCheckBox)->GetValue())
2440  {
2442  };
2444  };
2445  m_GLPreview->Refresh();
2446 };
2447 
2449  unsigned int image_number_in,
2450  wxToggleButton* identify_button_in,
2451  HuginBase::Panorama * m_pano_in)
2452 {
2453  image_number = image_number_in;
2454  m_identify_button = identify_button_in;
2455  m_pano = m_pano_in;
2456  // bind event handler
2457  Bind(wxEVT_ENTER_WINDOW, &ImageToogleButtonEventHandler::OnEnter, this);
2458  Bind(wxEVT_LEAVE_WINDOW, &ImageToogleButtonEventHandler::OnLeave, this);
2459  Bind(wxEVT_TOGGLEBUTTON, &ImageToogleButtonEventHandler::OnChange, this);
2460 }
2461 
2463 {
2464  // When using the identify tool, we want to identify image locations when
2465  // the user moves the mouse over the image buttons, but only if the image
2466  // is being shown.
2467  if (
2468  m_identify_button->GetValue() &&
2470  {
2471  std::vector<PreviewIdentifyTool**>::iterator it;
2472  for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2473  (*(*it))->ShowImageNumber(image_number);
2474  }
2475  }
2476  e.Skip();
2477 }
2478 
2480 {
2481  // if the mouse left one of the image toggle buttons with the identification
2482  // tool active, we should stop showing the image indicator for that button.
2483  if (
2484  m_identify_button->GetValue() &&
2486  {
2487  std::vector<PreviewIdentifyTool**>::iterator it;
2488  for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2489  (*(*it))->StopShowingImages();
2490  }
2491  }
2492  e.Skip();
2493 }
2494 
2496 {
2497  // the user is turning on or off an image using its button. We want to turn
2498  // the indicators on and off if appropriate correctly to. We use OnEnter
2499  // and OnLeave for the indicators, but these only work when the image is
2500  // showing, so we are carefull of the order:
2501  HuginBase::UIntSet activeImages = m_pano->getActiveImages();
2502  wxMouseEvent null_event;
2503  if (e.IsChecked()) {
2504  activeImages.insert(image_number);
2506  new PanoCommand::SetActiveImagesCmd(*m_pano, activeImages)
2507  );
2508  OnEnter(null_event);
2509  } else {
2510  OnLeave(null_event);
2511  activeImages.erase(image_number);
2513  new PanoCommand::SetActiveImagesCmd(*m_pano, activeImages)
2514  );
2515  }
2516 }
2517 
2519  identify_tools.push_back(identify_tool_in);
2520 }
2521 
2523  : image_number(image_number), frame(frame_in), m_pano(m_pano)
2524 {
2525  Bind(wxEVT_ENTER_WINDOW, &ImageGroupButtonEventHandler::OnEnter, this);
2526  Bind(wxEVT_LEAVE_WINDOW, &ImageGroupButtonEventHandler::OnLeave, this);
2527  Bind(wxEVT_CHECKBOX, &ImageGroupButtonEventHandler::OnChange, this);
2528 }
2529 
2531  identify_tools.push_back(identify_tool_in);
2532 }
2533 
2534 
2536 {
2537  //mark the image
2538  if (m_pano->getActiveImages().count(image_number))
2539  {
2540  std::vector<PreviewIdentifyTool**>::iterator it;
2541  for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2542  (*(*it))->ShowImageNumber(image_number);
2543  }
2544  }
2545  e.Skip();
2546 }
2547 
2549 {
2550  //unmark the image
2551  if (m_pano->getActiveImages().count(image_number))
2552  {
2553  std::vector<PreviewIdentifyTool**>::iterator it;
2554  for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2555  (*(*it))->StopShowingImages();
2556  }
2557  }
2558  e.Skip();
2559 }
2560 
2562 {
2563  wxMouseEvent null_event;
2564  if (e.IsChecked()) {
2566  OnEnter(null_event);
2567  } else {
2568  OnLeave(null_event);
2570  }
2571 }
2572 
2574  drag_tools.push_back(drag_tool_in);
2575 }
2576 
2578 {
2579  return m_DragModeChoice->GetSelection()==1 ||
2580  m_DragModeChoice->GetSelection()==3;
2581 }
2582 
2583 void GLPreviewFrame::ToggleImageInDragGroup(unsigned int image_nr, bool update_check_box) {
2584  if (imageDragGroup.count(image_nr) == 0) {
2585  this->AddImageToDragGroup(image_nr, update_check_box);
2586  } else {
2587  this->RemoveImageFromDragGroup(image_nr, update_check_box);
2588  }
2589 }
2590 void GLPreviewFrame::RemoveImageFromDragGroup(unsigned int image_nr, bool update_check_box) {
2591  imageDragGroup.erase(image_nr);
2592  if (update_check_box) {
2593  m_GroupToggleButtons[image_nr]->SetValue(false);
2594  }
2595 }
2596 void GLPreviewFrame::AddImageToDragGroup(unsigned int image_nr, bool update_check_box) {
2597  imageDragGroup.insert(image_nr);
2598  if (update_check_box) {
2599  m_GroupToggleButtons[image_nr]->SetValue(true);
2600  }
2601 }
2602 void GLPreviewFrame::SetDragGroupImages(HuginBase::UIntSet imageDragGroup_in, bool update_check_box) {
2603  imageDragGroup.swap(imageDragGroup_in);
2604  std::vector<wxCheckBox*>::iterator it;
2605  unsigned int nr = 0;
2606  for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2607  (*it)->SetValue(imageDragGroup.count(nr++)>0);
2608  }
2609 }
2611  return imageDragGroup;
2612 }
2613 void GLPreviewFrame::ClearDragGroupImages(bool update_check_box) {
2614  imageDragGroup.clear();
2615  std::vector<wxCheckBox*>::iterator it;
2616  for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2617  (*it)->SetValue(false);
2618  }
2619 }
2620 
2622 {
2623  std::vector<wxCheckBox*>::iterator it;
2624  for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it)
2625  {
2626  (*it)->Show(isShown);
2627  }
2628  Layout();
2629 };
2630 
2633 {
2635  m_differenceIndex=m_BlendModeChoice->Append(_("difference"));
2636  // update size
2637  m_BlendModeChoice->InvalidateBestSize();
2638  m_BlendModeChoice->GetParent()->Layout();
2639  Refresh();
2640  // get blend mode last state
2641  unsigned int oldMode = wxConfigBase::Get()->Read("/GLPreviewFrame/blendMode", 0l);
2642  // limit old state to max available states
2643  if (oldMode >= m_BlendModeChoice->GetCount())
2644  {
2645  oldMode = 0;
2646  }
2647  m_BlendModeChoice->SetSelection(oldMode);
2648  updateBlendMode();
2649 };
2650 
2651 void GLPreviewFrame::OnAutocrop(wxCommandEvent &e)
2652 {
2653  DEBUG_INFO("Dirty ROI Calc\n");
2654  if (m_pano.getActiveImages().empty())
2655  {
2656  return;
2657  };
2658 
2659  vigra::Rect2D newROI;
2660  {
2661  ProgressReporterDialog progress(0, _("Autocrop"), _("Calculating optimal crop"), this);
2662  HuginBase::CalculateOptimalROI cropPano(m_pano, &progress);
2663  cropPano.run();
2664  if (cropPano.hasRunSuccessfully())
2665  {
2666  newROI = cropPano.getResultOptimalROI();
2667  };
2668  };
2669 
2670  //set the ROI - fail if the right/bottom is zero, meaning all zero
2671  if(!newROI.isEmpty())
2672  {
2674  opt.setROI(newROI);
2677  );
2678  }
2679 }
2680 
2681 void GLPreviewFrame::OnStackAutocrop(wxCommandEvent &e)
2682 {
2683  DEBUG_INFO("Dirty ROI Calc\n");
2684  if (m_pano.getActiveImages().empty())
2685  {
2686  return;
2687  };
2688 
2689  vigra::Rect2D newROI;
2690  {
2691  ProgressReporterDialog progress(0, _("Autocrop"), _("Calculating optimal crop"), this);
2692  HuginBase::UIntSet activeImages = m_pano.getActiveImages();
2693  std::vector<HuginBase::UIntSet> stackImgs = getHDRStacks(m_pano, activeImages, m_pano.getOptions());
2694  HuginBase::CalculateOptimalROI cropPano(m_pano, &progress);
2695  //only use hdr autocrop for projects with stacks
2696  //otherwise fall back to "normal" autocrop
2697  if (stackImgs.size()<activeImages.size())
2698  {
2699  cropPano.setStacks(stackImgs);
2700  }
2701  cropPano.run();
2702  if (cropPano.hasRunSuccessfully())
2703  {
2704  newROI = cropPano.getResultOptimalROI();
2705  };
2706  };
2707 
2708  //set the ROI - fail if the right/bottom is zero, meaning all zero
2709  if(!newROI.isEmpty())
2710  {
2712  opt.setROI(newROI);
2715  );
2716  }
2717 }
2718 
2719 void GLPreviewFrame::OnAutocropOutside(wxCommandEvent& e)
2720 {
2721  DEBUG_INFO("Dirty ROI Calc\n");
2722  if (m_pano.getActiveImages().empty())
2723  {
2724  return;
2725  };
2726 
2727  vigra::Rect2D newROI;
2728  {
2729  ProgressReporterDialog progress(0, _("Autocrop"), _("Calculating optimal crop"), this);
2730  HuginBase::CalculateOptimalROIOutside cropPano(m_pano, &progress);
2731  cropPano.run();
2732  if (cropPano.hasRunSuccessfully())
2733  {
2734  newROI = cropPano.getResultOptimalROI();
2735  };
2736  };
2737 
2738  //set the ROI - fail if the right/bottom is zero, meaning all zero
2739  if (!newROI.isEmpty())
2740  {
2742  opt.setROI(newROI);
2745  );
2746  }
2747 }
2748 
2749 void GLPreviewFrame::OnFullScreen(wxCommandEvent & e)
2750 {
2751  ShowFullScreen(!IsFullScreen(), wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
2752 };
2753 
2754 void GLPreviewFrame::SetMode(int newMode)
2755 {
2756  if(m_mode==newMode)
2757  return;
2758  SetStatusText(wxEmptyString, 0); // blank status text as it refers to an old tool.
2759  switch(m_mode)
2760  {
2761  case mode_assistant:
2762  case mode_preview:
2763  // switch off identify and show cp tool
2764  identify_tool->setConstantOn(false);
2768  m_colorpicker_togglebutton->SetValue(false);
2769 // preview_helper->DeactivateTool(identify_tool);
2770 // panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool);
2771 // plane_overview_helper->DeactivateTool(plane_overview_identify_tool);
2773  m_editCP_togglebutton->SetValue(false);
2774 
2776  m_identify_togglebutton->SetValue(false);
2780  XRCCTRL(*this,"preview_control_point_tool",wxCheckBox)->SetValue(false);
2781  break;
2782  case mode_layout:
2783  // disable layout mode.
2787  // reactivate identify and camera tool when leaving layout mode
2792  m_GLPreview->SetLayoutMode(false);
2793  m_GLOverview->SetLayoutMode(false);
2794  // Switch the panorama mask back on.
2796  //restore blend mode
2798  updateBlendMode();
2799  break;
2800  case mode_projection:
2802  break;
2803  case mode_drag:
2807  if (individualDragging()) {
2808  std::vector<wxCheckBox*>::iterator it;
2809  for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2810  (*it)->Show(false);
2811  }
2812  }
2813  break;
2814  case mode_crop:
2818  break;
2819  };
2820  m_mode=newMode;
2821  wxScrollEvent dummy;
2822  switch(m_mode)
2823  {
2824  case mode_assistant:
2825  case mode_preview:
2826  break;
2827  case mode_layout:
2828  //save blend mode setting, set to normal for layout mode
2829  non_layout_blend_mode=m_BlendModeChoice->GetSelection();
2830  m_BlendModeChoice->SetSelection(0);
2831  updateBlendMode();
2832  // turn off things not used in layout mode.
2835  // deactivate identify tool in layout mode
2839  m_GLPreview->SetLayoutMode(true);
2840  m_GLOverview->SetLayoutMode(true);
2844  // we need to update the meshes after switch to layout mode
2845  // otherwise the following update of scale has no meshes to scale
2846  m_GLPreview->Update();
2847  m_GLOverview->Update();
2848  OnLayoutScaleChange(dummy);
2849  break;
2850  case mode_projection:
2852  break;
2853  case mode_drag:
2857  if (individualDragging()) {
2858  std::vector<wxCheckBox*>::iterator it;
2859  for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2860  (*it)->Show(true);
2861  }
2862  }
2863  break;
2864  case mode_crop:
2868  break;
2869  };
2870  //enable group checkboxes only for drag mode tab
2872  m_GLPreview->Refresh();
2873 };
2874 
2875 void GLPreviewFrame::OnSelectMode(wxNotebookEvent &e)
2876 {
2877  if(m_mode!=-1)
2878  SetMode(e.GetSelection());
2879 };
2880 
2881 void GLPreviewFrame::OnToolModeChanging(wxNotebookEvent &e)
2882 {
2883  if(m_pano.getNrOfImages()==0 && e.GetOldSelection()==0)
2884  {
2885  wxBell();
2886  e.Veto();
2887  };
2888 };
2889 
2890 void GLPreviewFrame::OnROIChanged ( wxCommandEvent & e )
2891 {
2893  long left, right, top, bottom;
2894  if (!m_ROITopTxt->GetValue().ToLong(&top)) {
2895  wxLogError(_("Top needs to be an integer bigger than 0"));
2896  return;
2897  }
2898  if (!m_ROILeftTxt->GetValue().ToLong(&left)) {
2899  wxLogError(_("left needs to be an integer bigger than 0"));
2900  return;
2901  }
2902  if (!m_ROIRightTxt->GetValue().ToLong(&right)) {
2903  wxLogError(_("right needs to be an integer bigger than 0"));
2904  return;
2905  }
2906  if (!m_ROIBottomTxt->GetValue().ToLong(&bottom)) {
2907  wxLogError(_("bottom needs to be an integer bigger than 0"));
2908  return;
2909  }
2910  opt.setROI(vigra::Rect2D(left, top, right, bottom));
2911  // make sure that left is really to the left of right
2912  if(opt.getROI().width()<1) {
2913  wxLogError(_("left boundary must be smaller than right"));
2915  return;
2916  }
2917  // make sure that top is really higher than bottom
2918  if(opt.getROI().height()<1) {
2919  wxLogError(_("top boundary must be smaller than bottom"));
2921  return;
2922  }
2923 
2926  );
2927 };
2928 
2929 void GLPreviewFrame::OnResetCrop(wxCommandEvent &e)
2930 {
2932  opt.setROI(vigra::Rect2D(0,0,opt.getWidth(),opt.getHeight()));
2934 };
2935 
2936 void GLPreviewFrame::OnSetCropAspect(wxCommandEvent& e)
2937 {
2938  // ask user for a setting
2939  SelectAspectRatioDialog dlg(this);
2940  if (dlg.ShowModal() == wxID_OK)
2941  {
2943  const double aspectRatio = dlg.GetSelectedAspectRatio();
2944  // calculate the new ROI, move crop if necessary
2945  int left = opt.getROI().left();
2946  int top = opt.getROI().top();
2947  int width = opt.getROI().width();
2948  int height = opt.getROI().height();
2949  const int newHeight = 1.0 * width / aspectRatio;
2950  if (newHeight > height)
2951  {
2952  const int newWidth = 1.0 * height * aspectRatio;
2953  left = left + (width - newWidth) / 2.0;
2954  width = newWidth;
2955  }
2956  else
2957  {
2958  top = top + (height - newHeight) / 2.0;
2959  height = newHeight;
2960  };
2961  // finally set new crop
2962  opt.setROI(vigra::Rect2D(left, top, left + width, top + height));
2964  };
2965 }
2966 
2967 void GLPreviewFrame::OnHFOVChanged ( wxCommandEvent & e )
2968 {
2970 
2971 
2972  wxString text = m_HFOVText->GetValue();
2973  DEBUG_INFO ("HFOV = " << text.mb_str(wxConvLocal) );
2974  if (text == wxEmptyString) {
2975  return;
2976  }
2977 
2978  double hfov;
2979  if (!hugin_utils::str2double(text, hfov)) {
2980  wxLogError(_("Value must be numeric."));
2981  return;
2982  }
2983 
2984  if ( hfov <=0 || hfov > opt.getMaxHFOV()) {
2985  wxLogError(wxString::Format(
2986  _("Invalid HFOV value. Maximum HFOV for this projection is %lf."),
2987  opt.getMaxHFOV()));
2988  hfov=opt.getMaxHFOV();
2989  }
2990  opt.setHFOV(hfov);
2991  // recalculate panorama height...
2994  );
2995 
2996  DEBUG_INFO ( "new hfov: " << hfov )
2997 };
2998 
2999 void GLPreviewFrame::OnVFOVChanged ( wxCommandEvent & e )
3000 {
3002 
3003  wxString text = m_VFOVText->GetValue();
3004  DEBUG_INFO ("VFOV = " << text.mb_str(wxConvLocal) );
3005  if (text == wxEmptyString) {
3006  return;
3007  }
3008 
3009  double vfov;
3010  if (!hugin_utils::str2double(text, vfov)) {
3011  wxLogError(_("Value must be numeric."));
3012  return;
3013  }
3014 
3015  if ( vfov <=0 || vfov > opt.getMaxVFOV()) {
3016  wxLogError(wxString::Format(
3017  _("Invalid VFOV value. Maximum VFOV for this projection is %lf."),
3018  opt.getMaxVFOV()));
3019  vfov = opt.getMaxVFOV();
3020  }
3021  opt.setVFOV(vfov);
3022  // recalculate panorama height...
3025  );
3026 
3027  DEBUG_INFO ( "new vfov: " << vfov )
3028 };
3029 
3031 {
3032  if(m_mode==mode_layout)
3033  {
3034  double scale_factor=XRCCTRL(*this,"layout_scale_slider",wxSlider)->GetValue();
3035  m_GLPreview->SetLayoutScale(10.0 - sqrt(scale_factor));
3036  m_GLOverview->SetLayoutScale(10.0 - sqrt(scale_factor));
3037  m_GLPreview->Refresh();
3038  m_GLOverview->Refresh();
3039  };
3040 };
3041 
3043 {
3045  double hfov = opts.getHFOV();
3046  double vfov = opts.getVFOV();
3047  double maxfov = hfov > vfov ? hfov : vfov;
3048  wxString message;
3049  // If this is set to true, offer rectilinear as an alternative if it fits.
3050  bool rectilinear_option = false;
3051  switch (opts.getProjection()) {
3053  if (maxfov > 120.0) {
3054  // wide rectilinear image
3055  message = _("With a wide field of view, panoramas with rectilinear projection get very stretched towards the edges.\n");
3056  if (vfov < 110) {
3057  message += _("Since the field of view is only very wide in the horizontal direction, try a cylindrical projection instead.");
3058  } else {
3059  message += _("For a very wide panorama, try equirectangular projection instead.");
3060  }
3061  message += " ";
3062  message += _("You could also try Panini projection.");
3063  }
3064  break;
3066  if (vfov > 120.0) {
3067  message = _("With a wide vertical field of view, panoramas with cylindrical projection get very stretched at the top and bottom.\nAn equirectangular projection would fit the same content in less vertical space.");
3068  } else rectilinear_option = true;
3069  break;
3071  if (vfov < 110.0 && hfov > 120.0)
3072  {
3073  message = _("Since the vertical field of view is not too wide, you could try setting the panorama projection to cylindrical.\nCylindrical projection preserves vertical lines, unlike equirectangular.");
3074  } else rectilinear_option = true;
3075  break;
3077  if (maxfov < 280.0) {
3078  rectilinear_option = true;
3079  message = _("Stereographic projection is conformal, unlike this Fisheye panorama projection.\nA conformal projection preserves angles around a point, which often makes it easier on the eye.");
3080  }
3081  break;
3083  if (maxfov > 300.0) {
3084  message = _("Panoramas with stereographic projection and a very wide field of view stretch the image around the edges a lot.\nThe Fisheye panorama projection compresses it, so you can fit in a wide field of view and still have a reasonable coverage of the middle.");
3085  } else rectilinear_option = true;
3086  break;
3087  default:
3088  rectilinear_option = true;
3089  }
3090  if (rectilinear_option && maxfov < 110.0) {
3091  message = _("Setting the panorama to rectilinear projection would keep the straight lines straight.");
3092  }
3093  if (message.IsEmpty()) {
3094  // no message needed.
3095  m_infoBar->Dismiss();
3096  } else {
3097  m_infoBar->ShowMessage(message, wxICON_INFORMATION);
3098  }
3099 };
3100 
3102 {
3103  m_showProjectionHints=new_value;
3105  {
3106  m_infoBar->Dismiss();
3107  };
3108 };
3109 
3111 {
3112  hugin_utils::HuginMessageBox(_("You have hidden the infobar, which shows hints about selection of projection.\nIf you want to see the bar again, activate the bar in the preferences again."),
3113  _("Hugin"), wxOK | wxICON_INFORMATION, this);
3114  wxConfigBase* cfg=wxConfigBase::Get();
3115  cfg->Write("/GLPreviewFrame/ShowProjectionHints", false);
3116  m_showProjectionHints=false;
3117  cfg->Flush();
3118  e.Skip();
3119 };
3120 
3121 void GLPreviewFrame::UpdateIdentifyTools(std::set<unsigned int> new_image_set)
3122 {
3123  if(identify_tool)
3124  {
3125  identify_tool->UpdateWithNewImageSet(new_image_set);
3126  };
3128  {
3130  };
3132  {
3134  };
3135 }
3136 
3138  m_preview_background_color = XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->GetColour();
3139  wxString c = m_preview_background_color.GetAsString(wxC2S_HTML_SYNTAX);
3140  wxConfigBase* cfg=wxConfigBase::Get();
3141  cfg->Write("/GLPreviewFrame/PreviewBackground", c);
3142  cfg->Flush();
3146  redrawPreview();
3147 }
3148 
3151 }
3152 
3153 void GLPreviewFrame::OnGuideChanged(wxCommandEvent &e)
3154 {
3155  if(preview_guide_tool)
3156  {
3157  int selection=e.GetSelection();
3159  //synchronize wxChoice in projection and crop tab
3160  m_GuideChoiceCrop->SetSelection(selection);
3161  m_GuideChoiceProj->SetSelection(selection);
3162  m_GuideChoiceDrag->SetSelection(selection);
3163  redrawPreview();
3164  };
3165 };
3166 
3168 {
3169  int old_selection=m_DragModeChoice->GetSelection();
3170  if(old_selection==wxNOT_FOUND)
3171  {
3172  old_selection=0;
3173  };
3174  m_DragModeChoice->Clear();
3175  m_DragModeChoice->Append(_("normal"));
3176  m_DragModeChoice->Append(_("normal, individual"));
3177  if(newLevel==GUI_EXPERT)
3178  {
3179  m_DragModeChoice->Append(_("mosaic"));
3180  m_DragModeChoice->Append(_("mosaic, individual"));
3181  m_DragModeChoice->SetSelection(old_selection);
3182  }
3183  else
3184  {
3185  if(old_selection>1)
3186  {
3187  m_DragModeChoice->SetSelection(old_selection-2);
3188  }
3189  else
3190  {
3191  m_DragModeChoice->SetSelection(old_selection);
3192  };
3193  };
3194  DragChoiceLayout(m_DragModeChoice->GetSelection());
3195  wxCommandEvent dummy;
3196  OnDragChoice(dummy);
3197 
3198  old_selection=m_OverviewModeChoice->GetSelection();
3199  m_OverviewModeChoice->Clear();
3200  m_OverviewModeChoice->Append(_("Panosphere (outside)"));
3201  m_OverviewModeChoice->Append(_("Panosphere (inside)"));
3202  if(newLevel==GUI_EXPERT)
3203  {
3204  m_OverviewModeChoice->Append(_("Mosaic plane"));
3205  };
3206  if(newLevel==GUI_EXPERT && old_selection==2)
3207  {
3208  m_OverviewModeChoice->SetSelection(2);
3209  }
3210  else
3211  {
3213  m_OverviewModeChoice->SetSelection(0);
3214  };
3215  if(newLevel==GUI_SIMPLE)
3216  {
3217 #ifdef __WXMAC__
3218  wxApp::s_macExitMenuItemId = XRCID("action_exit_preview");
3219 #endif
3220  if(m_guiLevel!=GUI_SIMPLE)
3221  {
3222  GetMenuBar()->Remove(0);
3223  GetMenuBar()->Insert(0, m_filemenuSimple, _("&File"));
3224  };
3225  SetTitle(MainFrame::Get()->GetTitle());
3226  }
3227  else
3228  {
3229 #ifdef __WXMAC__
3230  wxApp::s_macExitMenuItemId = XRCID("action_exit_hugin");
3231 #endif
3232  if(m_guiLevel==GUI_SIMPLE)
3233  {
3234  GetMenuBar()->Remove(0);
3235  GetMenuBar()->Insert(0, m_filemenuAdvanced, _("&File"));
3236  };
3237  SetTitle(_("Fast Panorama preview"));
3238  };
3239  m_guiLevel=newLevel;
3240  // update menu items
3241  switch(m_guiLevel)
3242  {
3243  case GUI_SIMPLE:
3244  GetMenuBar()->FindItem(XRCID("action_gui_simple"))->Check();
3245  break;
3246  case GUI_ADVANCED:
3247  GetMenuBar()->FindItem(XRCID("action_gui_advanced"))->Check();
3248  break;
3249  case GUI_EXPERT:
3250  GetMenuBar()->FindItem(XRCID("action_gui_expert"))->Check();
3251  break;
3252  };
3253 };
3254 
3255 void GLPreviewFrame::AddUserDefinedSequence(int id, const wxString& desc, const wxString& help)
3256 {
3257  if (id == -1)
3258  {
3259  m_createButton->GetSplitButtonMenu()->AppendSeparator();
3260  }
3261  else
3262  {
3263  m_createButton->GetSplitButtonMenu()->Append(id, desc, help);
3264  };
3265 };
3266 
3267 void GLPreviewFrame::AddUserDefinedAssistant(int id, const wxString& desc, const wxString& help)
3268 {
3269  if (id == -1)
3270  {
3271  m_alignButton->GetSplitButtonMenu()->AppendSeparator();
3272  }
3273  else
3274  {
3275  m_alignButton->GetSplitButtonMenu()->Append(id, desc, help);
3276  };
3277 };
3278 
3279 void GLPreviewFrame::OnShowMainFrame(wxCommandEvent &e)
3280 {
3281  MainFrame::Get()->Show();
3282  MainFrame::Get()->Raise();
3283 };
3284 
3285 void GLPreviewFrame::OnUserExit(wxCommandEvent &e)
3286 {
3287  Close();
3288 };
3289 
3291 {
3292  if (wxConfig::Get()->Read("/ShowFisheyeCropHint", 1l) == 1)
3293  {
3294  // show hint about crop and open tab when requested
3295  wxDialog dlg;
3296  wxXmlResource::Get()->LoadDialog(&dlg, NULL, "fisheye_show_crop_dlg");
3297  if (dlg.ShowModal() == wxID_OK)
3298  {
3299  MainFrame::Get()->ShowMaskEditor(0, true);
3300  };
3301  if (XRCCTRL(dlg, "fisheye_crop_dont_ask_checkbox", wxCheckBox)->IsChecked())
3302  {
3303  wxConfig::Get()->Write("/ShowFisheyeCropHint", 0l);
3304  };
3305  };
3306 }
3307 
3308 void GLPreviewFrame::OnLoadImages(wxCommandEvent& e)
3309 {
3310  // load all images with default lens type
3311  LoadImages(-1);
3312 }
3313 
3314 void GLPreviewFrame::LoadImages(int preferredLensType)
3315 {
3316  // load the images.
3317  PanoOperation::AddImageOperation addImage(preferredLensType);
3318  HuginBase::UIntSet images;
3319  PanoCommand::PanoCommand* cmd=addImage.GetCommand(wxGetActiveWindow(), m_pano, images, m_guiLevel);
3320  if(cmd==NULL)
3321  {
3322  return;
3323  }
3324  //distribute images only if the existing images are not connected
3325  //otherwise it would destruct the existing image pattern
3326  const bool distributeImages=m_pano.getNrOfCtrlPoints()==0;
3327 
3328  const long autoAlign = wxConfigBase::Get()->Read("/Assistant/autoAlign", HUGIN_ASS_AUTO_ALIGN);
3329  if (autoAlign)
3330  {
3332  wxCommandEvent dummy;
3333  OnAlign(dummy);
3334  }
3335  else
3336  {
3337  std::vector<PanoCommand::PanoCommand*> cmds;
3338  cmds.push_back(cmd);
3339  if(distributeImages)
3340  {
3341  cmds.push_back(new PanoCommand::DistributeImagesCmd(m_pano));
3342  cmds.push_back(new PanoCommand::CenterPanoCmd(m_pano));
3343  };
3345  combinedCmd->setName("add and distribute images");
3347  if(m_pano.getImage(0).isCircularCrop())
3348  {
3349  // show hint about crop for fisheye images
3350  // skip display if we read the information from our lens database
3351  HuginBase::FileMetaData metaData=m_pano.getImage(0).getFileMetadata();
3352  HuginBase::FileMetaData::const_iterator pos = metaData.find("readProjectionFromDB");
3353  if(!(pos != metaData.end() && pos->second == "true"))
3354  {
3356  };
3357  };
3358  };
3359 }
3360 
3361 void GLPreviewFrame::OnAlign( wxCommandEvent & e )
3362 {
3363  // run default assisant
3364  MainFrame::Get()->RunAssistant(this);
3365 }
3366 
3367 void GLPreviewFrame::OnCreate( wxCommandEvent & e )
3368 {
3369  PanoOutputDialog dlg(this, m_pano, m_guiLevel);
3370  if(dlg.ShowModal()==wxID_OK)
3371  {
3374  );
3375  wxCommandEvent dummy;
3376  MainFrame::Get()->OnDoStitch(dummy);
3377  };
3378 }
3379 
3380 // remove cp, relatively easy, we get the selected cp from the edit cp tool
3381 void GLPreviewFrame::OnRemoveCP(wxCommandEvent & e)
3382 {
3385  // ask user, if pano should be optimized
3386  long afterEditCPAction = wxConfig::Get()->Read("/EditCPAfterAction", 0l);
3387  bool optimize = false;
3388  if (afterEditCPAction == 0)
3389  {
3390  wxDialog dlg;
3391  wxXmlResource::Get()->LoadDialog(&dlg, this, "edit_cp_optimize_dialog");
3392  XRCCTRL(dlg, "edit_cp_text1", wxStaticText)->SetLabel(wxString::Format(_("%lu control points were removed from the panorama.\n\nShould the panorama now be re-optimized?"), static_cast<unsigned long int>(edit_cp_tool->GetFoundCPs().size())));
3393  XRCCTRL(dlg, "edit_cp_text2", wxStaticText)->SetLabel(wxString::Format(_("Current selected optimizer strategy is \"%s\"."), MainFrame::Get()->GetCurrentOptimizerString().c_str()));
3394  dlg.Fit();
3395  optimize = (dlg.ShowModal() == wxID_OK);
3396  if (XRCCTRL(dlg, "edit_cp_dont_show_again_checkbox", wxCheckBox)->GetValue())
3397  {
3398  if (optimize)
3399  {
3400  wxConfig::Get()->Write("/EditCPAfterAction", 1l);
3401  }
3402  else
3403  {
3404  wxConfig::Get()->Write("/EditCPAfterAction", 2l);
3405  };
3406  };
3407  }
3408  else
3409  {
3410  optimize = (afterEditCPAction == 1);
3411  }
3412  if (optimize)
3413  {
3414  // invoke optimization routine
3415  wxCommandEvent ev(wxEVT_COMMAND_BUTTON_CLICKED, XRCID("action_optimize"));
3416  MainFrame::Get()->GetEventHandler()->AddPendingEvent(ev);
3417  };
3418 };
3419 
3420 // some helper for cp generation
3421 // maximal width for remapping for cp generating
3422 #define MAX_DIMENSION 1600
3424 {
3425  size_t imgNr;
3426  vigra::BRGBImage image;
3427  vigra::BImage mask;
3428 };
3429 
3430 typedef std::vector<FindStruct> FindVector;
3431 typedef std::multimap<double, vigra::Diff2D> MapPoints;
3432 
3434 
3435 void GLPreviewFrame::OnCreateCP(wxCommandEvent & e)
3436 {
3438  vigra::Rect2D roi = edit_cp_tool->GetSelectedROI();
3440  // some checking of conditions
3441  if (imgs.empty())
3442  {
3443  hugin_utils::HuginMessageBox(_("The selected region contains no active image.\nPlease select a region which is covered by at least 2 images."),
3444  _("Hugin"), wxOK | wxICON_INFORMATION, this);
3445  return;
3446  };
3447  if (imgs.size() < 2)
3448  {
3449  hugin_utils::HuginMessageBox(_("The selected region is only covered by a single image.\nCan't create control points for a single image."),
3450  _("Hugin"), wxOK | wxICON_INFORMATION, this);
3451  return;
3452  };
3453  if (roi.width() > 0.25 * m_pano.getOptions().getWidth())
3454  {
3455  if (hugin_utils::HuginMessageBox(_("The selected rectangle is very big.\nThis function is only intended for smaller areas. Otherwise unwanted side effect can appear.\n\nProceed anyway?"),
3456  _("Hugin"), wxYES_NO | wxICON_INFORMATION, this) == wxNO)
3457  {
3458  return;
3459  };
3460  }
3462  opts.setROI(roi);
3463  // don't correct exposure
3464  opts.outputExposureValue = 0;
3465  // don't use GPU for remapping, this interfere with the fast preview window
3466  opts.remapUsingGPU = false;
3467  // rescale if size is too big
3468  if (roi.width() > MAX_DIMENSION)
3469  {
3470  opts.setWidth(opts.getWidth() * MAX_DIMENSION / roi.width(), true);
3471  roi = opts.getROI();
3472  };
3473  HuginBase::CPVector cps;
3474  {
3475  ProgressReporterDialog progress(2*imgs.size()+1, _("Searching control points"), _("Processing"), this);
3476  // remap all images to panorama projection
3477  FindVector cpInfos;
3478  HuginBase::CPVector tempCps;
3479  for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
3480  {
3481  const size_t imgNr = *it;
3482  if (!progress.updateDisplayValue(_("Remap image to panorama projection...")))
3483  {
3484  return;
3485  };
3486  FindStruct findStruct;
3487  findStruct.imgNr = imgNr;
3488  // remap image to panorama projection
3489  ImageCache::ImageCacheRGB8Ptr CachedImg = ImageCache::getInstance().getImage(m_pano.getImage(imgNr).getFilename())->get8BitImage();
3490 
3492  HuginBase::SrcPanoImage srcImg = m_pano.getSrcImage(imgNr);
3493  // don't correct exposure
3494  srcImg.setExposureValue(0);
3495  remapped->setPanoImage(srcImg, opts, roi);
3496  remapped->remapImage(vigra::srcImageRange(*CachedImg), vigra_ext::INTERP_CUBIC, &progress);
3497  if (!progress.updateDisplay())
3498  {
3499  delete remapped;
3500  return;
3501  };
3502  findStruct.image = remapped->m_image;
3503  findStruct.mask = remapped->m_mask;
3504  delete remapped;
3505  cpInfos.push_back(findStruct);
3506  };
3507  if (cpInfos.size() > 1)
3508  {
3509  // match keypoints in all image pairs
3510  // select a sensible grid size depending on ratio of selected region, maximal should it be 25 regions
3511  unsigned gridx = hugin_utils::roundi(sqrt((double)roi.width() / (double)roi.height() * 25));
3512  if (gridx < 1)
3513  {
3514  gridx = 1;
3515  }
3516  unsigned gridy = hugin_utils::roundi(25 / gridx);
3517  if (gridy < 1)
3518  {
3519  gridy = 1;
3520  }
3521  while (roi.width() / gridx < 20 && gridx > 1)
3522  {
3523  --gridx;
3524  };
3525  while (roi.height() / gridy < 20 && gridy > 1)
3526  {
3527  --gridy;
3528  };
3529  // template width
3530  const long templWidth = 20;
3531  // search width
3532  const long sWidth = 100;
3533  // match all images with all
3534  for (size_t img1 = 0; img1 < cpInfos.size() - 1; ++img1)
3535  {
3536  if (!progress.updateDisplayValue(_("Matching interest points...")))
3537  {
3538  return;
3539  };
3540  vigra::Size2D size(cpInfos[img1].image.width(), cpInfos[img1].image.height());
3541  // create a number of sub-regions
3542  std::vector<vigra::Rect2D> rects;
3543  for (unsigned party = 0; party < gridy; party++)
3544  {
3545  for (unsigned partx = 0; partx < gridx; partx++)
3546  {
3547  vigra::Rect2D rect(partx*size.x / gridx, party*size.y / gridy,
3548  (partx + 1)*size.x / gridx, (party + 1)*size.y / gridy);
3549  rect &= vigra::Rect2D(size);
3550  if (rect.width()>0 && rect.height()>0)
3551  {
3552  rects.push_back(rect);
3553  };
3554  };
3555  };
3556 
3557  if (!progress.updateDisplay())
3558  {
3559  return;
3560  };
3561 
3562 #pragma omp parallel for schedule(dynamic)
3563  for (int i = 0; i < rects.size(); ++i)
3564  {
3565  MapPoints points;
3566  vigra::Rect2D rect(rects[i]);
3567  // run interest point detection in sub-region
3568  vigra_ext::findInterestPointsPartial(srcImageRange(cpInfos[img1].image, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >()), rect, 2, 5 * 8, points);
3569  //check if all points are inside the given image
3570  MapPoints validPoints;
3571  for (MapPoints::const_iterator it = points.begin(); it != points.end(); ++it)
3572  {
3573  if (cpInfos[img1].mask(it->second.x, it->second.y)>0)
3574  {
3575  validPoints.insert(*it);
3576  };
3577  };
3578 
3579  if (!validPoints.empty())
3580  {
3581  // now fine-tune the interest points with all other images
3582  for (size_t img2 = img1 + 1; img2 < cpInfos.size(); ++img2)
3583  {
3584  unsigned nGood = 0;
3585  // loop over all points, starting with the highest corner score
3586  for (MapPoints::const_reverse_iterator it = validPoints.rbegin(); it != validPoints.rend(); ++it)
3587  {
3588  if (nGood >= 2)
3589  {
3590  // we have enough points, stop
3591  break;
3592  }
3593  //check if point is covered by second image
3594  if (cpInfos[img2].mask(it->second.x, it->second.y) == 0)
3595  {
3596  continue;
3597  };
3598  // finally fine-tune point
3599  vigra_ext::CorrelationResult res = vigra_ext::PointFineTune(cpInfos[img1].image, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >(), it->second, templWidth,
3600  cpInfos[img2].image, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >(), it->second, sWidth);
3601  if (res.maxi < 0.9)
3602  {
3603  continue;
3604  }
3605  nGood++;
3606  // add control point
3607  {
3608  hugin_omp::ScopedLock sl(cpLock);
3609  tempCps.push_back(HuginBase::ControlPoint(cpInfos[img1].imgNr, it->second.x, it->second.y,
3610  cpInfos[img2].imgNr, res.maxpos.x, res.maxpos.y, HuginBase::ControlPoint::X_Y));
3611  };
3612  };
3613  };
3614  };
3615  };
3616  // free memory
3617  cpInfos[img1].image.resize(0, 0);
3618  cpInfos[img1].mask.resize(0, 0);
3619  };
3620 
3621  // transform coordinates back to image space
3622  for (size_t i = 0; i < tempCps.size(); ++i)
3623  {
3624  HuginBase::ControlPoint cp = tempCps[i];
3625  hugin_utils::FDiff2D p1(cp.x1 + roi.left(), cp.y1 + roi.top());
3626  hugin_utils::FDiff2D p1Img;
3627  HuginBase::PTools::Transform transform;
3628  transform.createTransform(m_pano.getImage(cp.image1Nr), opts);
3629  if (transform.transformImgCoord(p1Img, p1))
3630  {
3631  hugin_utils::FDiff2D p2(cp.x2 + roi.left(), cp.y2 + roi.top());
3632  hugin_utils::FDiff2D p2Img;
3633  transform.createTransform(m_pano.getImage(cp.image2Nr), opts);
3634  if (transform.transformImgCoord(p2Img, p2))
3635  {
3636  cp.x1 = p1Img.x;
3637  cp.y1 = p1Img.y;
3638  cp.x2 = p2Img.x;
3639  cp.y2 = p2Img.y;
3640  cps.push_back(cp);
3641  };
3642  };
3643  };
3644 
3645  if (!cps.empty())
3646  {
3647  // check newly found control points
3648  // create copy
3650  // remove all cps and set only the new found cp
3651  copyPano.setCtrlPoints(cps);
3652  // now create a subpano with only the selected images
3653  HuginBase::Panorama subPano = copyPano.getSubset(imgs);
3654  // clean control points
3655  if (!progress.updateDisplayValue(_("Checking results...")))
3656  {
3657  return;
3658  };
3660  HuginBase::UIntSet invalidCP = HuginBase::getCPoutsideLimit(subPano);
3662  if (!invalidCP.empty())
3663  {
3664  for (HuginBase::UIntSet::const_reverse_iterator it = invalidCP.rbegin(); it != invalidCP.rend(); ++it)
3665  {
3666  cps.erase(cps.begin() + *it);
3667  };
3668  }
3669  // force closing progress dialog
3670  if (!progress.updateDisplayValue())
3671  {
3672  return;
3673  };
3675  // ask user, if pano should be optimized
3676  long afterEditCPAction = wxConfig::Get()->Read("/EditCPAfterAction", 0l);
3677  bool optimize = false;
3678  if (afterEditCPAction == 0)
3679  {
3680  // close progress window, otherwise the dialog don't autoamtically get the focus
3681  wxYield();
3682  wxDialog dlg;
3683  wxXmlResource::Get()->LoadDialog(&dlg, this, "edit_cp_optimize_dialog");
3684  XRCCTRL(dlg, "edit_cp_text1", wxStaticText)->SetLabel(wxString::Format(_("%lu control points were added to the panorama.\n\nShould the panorama now be re-optimized?"), static_cast<unsigned long int>(cps.size())));
3685  XRCCTRL(dlg, "edit_cp_text2", wxStaticText)->SetLabel(wxString::Format(_("Current selected optimizer strategy is \"%s\"."), MainFrame::Get()->GetCurrentOptimizerString().c_str()));
3686  dlg.Fit();
3687  optimize = (dlg.ShowModal() == wxID_OK);
3688  if (XRCCTRL(dlg, "edit_cp_dont_show_again_checkbox", wxCheckBox)->GetValue())
3689  {
3690  if (optimize)
3691  {
3692  wxConfig::Get()->Write("/EditCPAfterAction", 1l);
3693  }
3694  else
3695  {
3696  wxConfig::Get()->Write("/EditCPAfterAction", 2l);
3697  };
3698  };
3699  }
3700  else
3701  {
3702  optimize = (afterEditCPAction == 1);
3703  }
3704  if (optimize)
3705  {
3706  // invoke optimization routine
3707  wxCommandEvent ev(wxEVT_COMMAND_BUTTON_CLICKED, XRCID("action_optimize"));
3708  MainFrame::Get()->GetEventHandler()->AddPendingEvent(ev);
3709  };
3710  };
3711  };
3712  };
3713  // finally redraw
3714  m_GLPreview->Update();
3715  m_GLPreview->Refresh();
3716 };
3717 
3718 void GLPreviewFrame::OnSelectAllMenu(wxCommandEvent& e)
3719 {
3720  wxConfig::Get()->Write("/GLPreviewFrame/SelectAllMode", 0l);
3722 };
3723 
3724 void GLPreviewFrame::OnSelectMedianMenu(wxCommandEvent& e)
3725 {
3726  wxConfig::Get()->Write("/GLPreviewFrame/SelectAllMode", 1l);
3728 };
3729 
3731 {
3732  wxConfig::Get()->Write("/GLPreviewFrame/SelectAllMode", 2l);
3734 };
3735 
3737 {
3738  wxConfig::Get()->Write("/GLPreviewFrame/SelectAllMode", 3l);
3740 };
3741 
3743 {
3744  wxConfig::Get()->Write("/GLPreviewFrame/SelectAllKeepSelection", true);
3745  m_selectKeepSelection = true;
3746 };
3747 
3749 {
3750  wxConfig::Get()->Write("/GLPreviewFrame/SelectAllKeepSelection", false);
3751  m_selectKeepSelection = false;
3752 }
3753 
3754 void GLPreviewFrame::OnImageContextMenu(wxContextMenuEvent& e)
3755 {
3756  // store image number
3757  m_imageMenuIndex = e.GetId() - ID_TOGGLE_BUT;
3758  m_imageMenu.FindItem(m_removeImageMenuId)->SetItemLabel(wxString::Format(_("Remove image %s"), m_ToggleButtons[m_imageMenuIndex]->GetToolTipText()));
3759  // show popup menu
3760  PopupMenu(&m_imageMenu);
3761 }
3762 
3763 void GLPreviewFrame::OnRemoveImage(wxCommandEvent& e)
3764 {
3765  // remove image as selected with context menu
3766  if (m_imageMenuIndex != -1)
3767  {
3769  m_imageMenuIndex = -1;
3770  }
3771 }
HuginBase::UIntSet GetDragGroupImages()
AlphaImage m_mask
corresponding alpha channel
Definition: ROIImage.h:274
#define DEBUG_INFO(msg)
Definition: utils.h:69
int floori(double x)
Definition: hugin_math.h:65
void setConstantOn(bool constant_on_in)
tool for the manipulation of the opengl &#39;camera&#39; properties It handles rotation of the camera positio...
wxSlider * m_HFOVSlider
Base class for all panorama commands.
Definition: Command.h:38
wxTextCtrl * m_ROITopTxt
wxTextCtrl * m_rangeCompressionTextCtrl
PlaneOverviewCameraTool * plane_overview_camera_tool
SelectAllMode m_selectAllMode
HuginBase::Panorama & m_pano
Definition: PreviewFrame.h:95
Allow the user to change the cropping region by dragging it in the fast preview.
int gcd(int a, int b)
function to calculate greated common divisor using Euclidean algorithm both arguments should be &gt;=0 ...
Definition: hugin_math.cpp:35
PanoramaOptions::ProjectionFormat getProjection() const
#define HUGIN_SHOW_PROJECTION_HINTS
void OnRangeCompressionDecrease(wxSpinEvent &e)
std::vector< UIntSet > getHDRStacks(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output stacks
Definition: LayerStacks.cpp:35
void AddDragTool(DragTool **drag_tool_in)
wxSpinButton * m_exposureSpinBut
implementation of huginApp Class
update variables of a group of images
Definition: PanoCommand.h:174
declaration of functions to handle stacks and layers
std::vector< wxToggleButton * > m_ToggleButtons
void OnRemoveCP(wxCommandEvent &e)
handler to remove cp
PreviewCropTool * crop_tool
void OnControlPoint(wxCommandEvent &e)
PreviewDifferenceTool * panosphere_difference_tool
std::set< Tool * > ActivateTool(Tool *tool)
Definition: ToolHelper.cpp:53
void OnCreate(wxCommandEvent &e)
wxGLContext * GetContext()
Definition: GLViewer.h:78
PreviewIdentifyTool * identify_tool
void SetStatusMessage(wxString message)
The OpenGL preview frame.
void AddIdentifyTool(PreviewIdentifyTool **identify_tool_in)
virtual PanoCommand::PanoCommand * GetCommand(wxWindow *parent, HuginBase::Panorama &pano, HuginBase::UIntSet images, GuiLevel guiLevel)
returns the appropriate PanoCommand::PanoCommand to be inserted into GlobalCmdHistory, checks if operation is enabled
void setHeight(unsigned int h)
set panorama height
void OnIdentify(wxCommandEvent &e)
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition: wxutils.cpp:67
pano_projection_features m_projFeatures
int roundi(T x)
Definition: hugin_math.h:73
wxChoice * m_DragModeChoice
wxColour GetPreviewBackgroundColor()
void OnShowAll(wxCommandEvent &e)
void StorePositionAndSize()
store position and size of window in wxConfig
#define HUGIN_PREVIEW_BACKGROUND
void setPanoImage(const SrcPanoImage &src, const PanoramaOptions &dest, vigra::Rect2D roi)
static double calcMeanExposure(const PanoramaData &pano)
vigra::BImage mask
wxBoxSizer * m_topsizer
bool str2double(const wxString &s, double &d)
Definition: wxPlatform.cpp:37
void AddUserDefinedAssistant(int id, const wxString &desc, const wxString &help)
adds the given user defined assistant to SplitButton menu
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition: wxutils.cpp:106
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
PreviewDragTool * drag_tool
GLwxAuiFloatingFrame * CreateFloatingFrame(wxWindow *parent, const wxAuiPaneInfo &p)
std::vector< ImageToogleButtonEventHandler * > toogle_button_event_handlers
PanosphereOverviewCameraTool * panosphere_overview_camera_tool
void OnColorPicker(wxCommandEvent &e)
event handler when starting color picker
tool for the manipulation of the opengl &#39;camera&#39; properties It handles zooming in/out of the main pre...
center panorama horizontically
Definition: PanoCommand.h:250
void ClearDragGroupImages(bool update_check_box=true)
bool isCircularCrop() const
returns true, if projection requires cicular crop
bool fovCalcSupported(ProjectionFormat f) const
true, if FOV calcuations are supported for projection f
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
Definition: Panorama.cpp:1551
void ToggleImageInDragGroup(unsigned int image_nr, bool update_check_box=true)
void OnVFOVChanged(wxCommandEvent &e)
GuiLevel m_guiLevel
virtual void SetLayoutScale(double scale)
Definition: GLViewer.cpp:301
ImageToogleButtonEventHandler(unsigned int image_number, wxToggleButton *identify_button_in, HuginBase::Panorama *m_pano)
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
wxPanel * m_overviewCommandPanel
void OnOverviewToggle(wxCommandEvent &e)
wxTextCtrl * m_ROIRightTxt
void SetPhotometricCorrect(bool state)
Definition: GLViewer.cpp:289
SplitButton * m_createButton
CorrelationResult PointFineTune(const IMAGET &templImg, ACCESSORT access_t, vigra::Diff2D templPos, int templSize, const IMAGES &searchImg, ACCESSORS access_s, vigra::Diff2D searchPos, int sWidth)
fine tune a point with normalized cross correlation
Definition: Correlation.h:504
#define DEBUG_TRACE(msg)
Definition: utils.h:67
void OnDecreaseExposure(wxSpinEvent &e)
wxBitmapButton * m_defaultExposureBut
void OnEnter(wxMouseEvent &e)
void RunAssistant(wxWindow *mainWin, const wxString &userdefinedAssistant=wxEmptyString)
Definition: MainFrame.cpp:2377
void registerPTWXDlgFcn()
Definition: PTWXDlg.cpp:178
void OnSwitchPreviewGrid(wxCommandEvent &e)
event handler for switch on/off grid on preview
unsigned int getHeight() const
get panorama height
void SetActive(bool active)
Definition: GLViewer.h:75
UIntSet getImagesinROI(const PanoramaData &pano, const UIntSet activeImages)
returns set of images which are visible in output ROI
void OnShowMainFrame(wxCommandEvent &e)
event handler to show main frame
some helper classes for graphes
GLPreview * m_GLPreview
void Resized(wxSizeEvent &e)
Definition: GLViewer.cpp:356
double getMaxHFOV() const
get maximum possible hfov with current projection
wxColour m_preview_background_color
virtual void setName(const std::string &newName)
sets the name for the command
Definition: Command.cpp:88
PreviewLayoutLinesTool * m_plane_layoutLinesTool
std::vector< wxCheckBox * > m_GroupToggleButtons
void AddImageToDragGroup(unsigned int image_nr, bool update_check_box=true)
void deregisterPTWXDlgFcn()
Definition: PTWXDlg.cpp:185
virtual void DeactivateTool(Tool *tool)
Definition: ToolHelper.cpp:60
Dialog for setting output parameters for simple user interface.
wxChoice * m_ProjectionChoice
Definition: PreviewFrame.h:102
std::size_t getNrOfCtrlPoints() const
number of control points
Definition: Panorama.h:306
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
wxMenu * GetSplitButtonMenu()
returns a pointer to the drop down menu
Definition: SplitButton.cpp:64
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
PreviewIdentifyTool * plane_overview_identify_tool
void OnSelectDarkestMenu(wxCommandEvent &e)
HuginBase::ImageCache::ImageCacheRGB8Ptr ImageCacheRGB8Ptr
Definition: wxImageCache.h:33
Translate the panorama.
Definition: PanoCommand.h:462
void setProjectionParameters(const std::vector< double > &params)
set the optional parameters (they need to be of the correct size)
PreviewPanoMaskTool * pano_mask_tool
simple class that forward the drop to the mainframe
Definition: MainFrame.h:61
include file for the hugin project
#define MAX_DIMENSION
void SetMenuProcessed()
reset popup menu status
void ForceRequireRedraw()
Definition: ViewState.cpp:439
wxNotebook * m_tool_notebook
void InitPreviews()
init previews
virtual void run()
runs the algorithm.
Panorama getSubset(const UIntSet &imgs) const
get a subset of the panorama
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition: Panorama.h:319
PreviewControlPointTool * preview_control_point_tool
std::vector< wxPanel * > m_ToggleButtonPanel
std::vector< PreviewIdentifyTool ** > identify_tools
void UpdateRoiDisplay(const HuginBase::PanoramaOptions opts)
update display of ROI
void OnPhotometric(wxCommandEvent &e)
wxTextCtrl * m_ROILeftTxt
remove several control points
Definition: PanoCommand.h:307
represents a control point
Definition: ControlPoint.h:38
PreviewDifferenceTool * plane_difference_tool
std::vector< PreviewIdentifyTool ** > identify_tools
Definition of PanoOperation class.
void findInterestPointsPartial(vigra::triple< ImageIter, ImageIter, ImageAcc > img, const vigra::Rect2D &rect, double scale, unsigned nPoints, std::multimap< double, vigra::Diff2D > &points)
void OnChange(wxCommandEvent &e)
void SetBitmap(const wxBitmapBundle &bitmap)
sets bitmap bundle
void RemoveImageFromDragGroup(unsigned int image_nr, bool update_check_box=true)
wxChoice * m_GuideChoiceCrop
PanosphereOverviewOutlinesTool * overview_outlines_tool
std::vector< HuginBase::UIntSet > Components
stores the components of the graph
Definition: ImageGraph.h:50
std::string doubleToString(double d, int digits)
convert a double to a string, suitable for display within a GUI.
Definition: utils.cpp:228
static huginApp * Get()
hack.. kind of a pseudo singleton...
Definition: huginApp.cpp:651
PanosphereSphereTool * panosphere_sphere_tool
void DeactivateTool(Tool *tool)
Definition: ToolHelper.cpp:704
void FillBlendChoice()
fills the blend wxChoice with all valid blend modes and restore the last used one ...
void OnActivate(wxActivateEvent &evt)
wxChoice * m_GuideChoiceDrag
PanoCommand to combine other PanoCommands.
Definition: PanoCommand.h:39
Panorama duplicate() const
duplicate the panorama
Definition: Panorama.cpp:1653
wxStaticBoxSizer * m_ToggleButtonSizer
void OnLeave(wxMouseEvent &e)
void OnSetCropAspect(wxCommandEvent &e)
event handler to set fixed aspect ratio of crop
void OnAutocropOutside(wxCommandEvent &e)
static hugin_omp::Lock cpLock
std::vector< LensInfo > LensInfoVector
vector of LensInfo to hold all available lens types
Definition: LensTools.h:48
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
helper for OpenMP
set the panorama options
Definition: PanoCommand.h:418
GLwxAuiFloatingFrame(wxWindow *parent, GLwxAuiManager *owner_mgr, const wxAuiPaneInfo &pane, wxWindowID id=wxID_ANY, long style=wxRESIZE_BORDER|wxSYSTEM_MENU|wxCAPTION|wxFRAME_FLOAT_ON_PARENT|wxCLIP_CHILDREN)
void OnRemoveImage(wxCommandEvent &e)
void OnDefaultExposure(wxCommandEvent &e)
wxSlider * m_VFOVSlider
void OnOverviewModeChoice(wxCommandEvent &e)
algorithms for remove control points by statistic method
void OnProjParameterChanged(wxCommandEvent &e)
#define DEBUG_WARN(msg)
Definition: utils.h:74
HuginBase::PanoramaOptions GetNewPanoramaOptions()
Draws guide lines over the panorama in fast preview window.
void LoadOpenGLLayout()
loads the layout of the OpenGL windows and restores it
wxChoice * m_ProjectionChoice
Finds the topmost image underneath the mouse pontier, cancel it&#39;s normal drawing, and then subtract i...
const vigra::Rect2D & getROI() const
void SetMode(OverviewMode mode)
Definition: GLViewer.cpp:492
Model for a panorama.
Definition: Panorama.h:152
wxSpinButton * m_rangeCompressionSpinBut
void OnHFOVChanged(wxCommandEvent &e)
void OnExposureChanged(wxCommandEvent &e)
wxMenu * m_filemenuSimple
wxBoxSizer * m_ButtonSizer
void SetLabel(const wxString &label) override
set the label string
virtual ~GLPreviewFrame()
dtor.
PreviewLayoutLinesTool * m_panosphere_layoutLinesTool
void OnStackAutocrop(wxCommandEvent &e)
#define PF_STYLE
GLwxAuiManager * m_mgr
The dock manager.
void MakePreviewTools(PreviewToolHelper *helper)
void SetMode(int newMode)
virtual void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &changed)
notifies about changes to images
VariableMapVector getVariables() const
get variables of this panorama
Definition: Panorama.cpp:118
void OnFullScreen(wxCommandEvent &e)
event handler for full screen
void OnSelectMedianMenu(wxCommandEvent &e)
std::vector< wxSlider * > m_projParamSlider
wxScrolledWindow * m_ButtonPanel
void OnLayoutScaleChange(wxCommandEvent &e)
event handler for change scale of layout mode
void resetProjectionParameters()
sets the optional parameters to their default values
void SetDragGroupImages(HuginBase::UIntSet imageDragGroup_in, bool update_check_box=true)
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
static MainFrame * Get()
hack.. kind of a pseudo singleton...
Definition: MainFrame.cpp:2130
remove an image from a panorama
Definition: PanoCommand.h:79
wxTextCtrl * m_VFOVText
Definition of PanoOutputDialog class.
The PreviewCropTool shows lines between the ends of control points in the fast preview.
WXIMPEX HuginLensTools::LensInfoVector GetLensProjectionList()
return a vector with all available projections
Definition: LensTools.cpp:46
interface to ToolHelper for drawing guide lines over pano
void AddUserDefinedSequence(int id, const wxString &desc, const wxString &help)
adds the given user defined output sequence to SplitButton menu
void SetGuiLevel(GuiLevel newLevel)
sets the gui level
void OnEnter(wxMouseEvent &e)
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
Definition: Panorama.cpp:449
SplitButton * m_selectAllButton
float pow(float a, double b)
Definition: utils.h:181
void AddIdentifyTool(PreviewIdentifyTool **identify_tool_in)
void redrawPreview()
Display an updated version of the preview images.
wxMenu * LoadMenu(const wxString &name)
loads the drop down menu from the XRC ressource
void remapImage(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra_ext::Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
remap a image without alpha channel
PreviewIdentifyTool * panosphere_overview_identify_tool
virtual vigra::Rect2D getResultOptimalROI()
return the ROI structure?, for now area
void OnSelectKeepSelection(wxCommandEvent &e)
wxMenu * m_filemenuAdvanced
double getMaxVFOV() const
get maximum possible vfov with current projection
Definition of dialog for selecting and editing aspect ratios of crop.
virtual double getResultHeight()
Definition: FitPanorama.h:75
std::vector< FindStruct > FindVector
PanoOperation to add several user selected images to the panorama.
Definition: PanoOperation.h:73
PlaneOverviewOutlinesTool * plane_overview_outlines_tool
std::vector< wxTextCtrl * > m_projParamTextCtrl
Maximum of correlation, position and value.
Definition: Correlation.h:56
HuginBase::Panorama * m_pano
std::string getLastCommandName() const
returns the name of the last command
wxInfoBar * m_infoBar
Bar for context sensitive projection information.
void OnToolModeChanging(wxNotebookEvent &e)
event handler for blocking changing mode when panorama contains no images
wxToggleButton * m_editCP_togglebutton
OverviewMode GetMode()
Definition: GLViewer.h:151
wxwindows specific panorama commands
std::map< std::string, std::string > FileMetaData
typedef for general map for storing metadata in files
Definition: SrcPanoImage.h:55
SplitButton * m_loadImagesButton
std::vector< HuginBase::UIntVector > getSortedStacks(const HuginBase::Panorama *pano)
returns vector of UIntVector with image numbers of each stack sorted by exposure
PreviewControlPointTool * plane_control_point_tool
distributes all images above the sphere, for the assistant
Definition: PanoCommand.h:649
wxPanel * m_projection_panel
void OnRangeCompressionChanged(wxCommandEvent &e)
void SetShowProjectionHints(bool new_value)
set status if projection hints should be shown or not
void UpdateIdentifyTools(std::set< unsigned int > new_image_set)
static GlobalCmdHist & getInstance()
PanosphereOverviewToolHelper * panosphere_overview_helper
virtual void SetLayoutMode(bool state)
Definition: GLViewer.cpp:295
std::multimap< double, vigra::Diff2D > MapPoints
implementation of PanosphereSphereTool Class
void MakePanosphereOverviewTools(PanosphereOverviewToolHelper *helper)
void ShowMaskEditor(size_t imgNr, bool switchToCropMode=false)
opens the mask/crop editor with the given image selected
Definition: MainFrame.cpp:2001
void SetGuideStyle(const Guides newGuideStyle)
sets the guide style to the given style
std::vector< ImageGroupButtonEventHandler * > toggle_group_button_event_handlers
wxToggleButton * m_identify_togglebutton
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
void OnProjectionChoice(wxCommandEvent &e)
PreviewControlPointTool * panosphere_control_point_tool
PanosphereOverviewProjectionGridTool * overview_projection_grid
Tool to delete all cp in a selected rectangle.
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
Definition: utils.h:114
double GetSelectedAspectRatio() const
returns the selected aspect ratio
VisualizationState * m_visualization_state
Definition: GLViewer.h:71
void EnableGroupCheckboxes(bool isShown)
changes the visibility of the group check boxes
void OnSelectMode(wxNotebookEvent &e)
event handler for selection of new mode
void setROI(const vigra::Rect2D &val)
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
Definition: ROIImage.h:287
void ShowFisheyeCropHint()
void KeypressEvent(int keycode, int modifiers, bool pressed)
Definition: ToolHelper.cpp:166
void DragChoiceLayout(int index)
void OnSelectBrightestMenu(wxCommandEvent &e)
straighten panorama horizontically
Definition: PanoCommand.h:259
compute interest points
The PreviewLayoutLinesTool handles the lines connecting images in the layout view of the fast preview...
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
void MakePlaneOverviewTools(PlaneOverviewToolHelper *helper)
#define HUGIN_ASS_AUTO_ALIGN
OverviewDragTool * overview_drag_tool
GLOverview * m_GLOverview
bool m_selectKeepSelection
GLPreviewFrame(wxFrame *frame, HuginBase::Panorama &pano)
ctor.
void OnCenterHorizontally(wxCommandEvent &e)
virtual void SetLayoutScale(double scale)
Definition: GLViewer.cpp:314
void OnROIChanged(wxCommandEvent &e)
event handler for changed roi
wxChoice * m_BlendModeChoice
std::vector< DragTool ** > drag_tools
wxBoxSizer * m_projParamSizer
tool to draw a whiteish transparent sphere for the panosphere
void OnLoadImages(wxCommandEvent &e)
void ShowProjectionWarnings()
Tell the user anything suspicious about the projection choice.
void OnUserExit(wxCommandEvent &e)
user wants to quit program
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
void OnGuideChanged(wxCommandEvent &e)
event handler when user selects different guide
void UpdateWithNewImageSet(std::set< unsigned int > new_image_set)
void OnShowNone(wxCommandEvent &e)
void addObserver(PanoramaObserver *o)
add a panorama observer.
Definition: Panorama.cpp:1546
void OnDoStitch(wxCommandEvent &e)
Definition: MainFrame.cpp:1651
void OnChangeProjectionParam(wxScrollEvent &e)
void setDragMode(DragMode drag_mode)
Definition: DragTool.cpp:47
unsigned int getWidth() const
include file for the hugin project
virtual void SetLayoutMode(bool state)
Definition: GLViewer.cpp:307
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
void OnSelectAllMenu(wxCommandEvent &e)
handle all options of select all context menu
void OnSelectResetSelection(wxCommandEvent &e)
Handle EVT_KILL_FOCUS and convert it to a EVT_TEXT_ENTER event.
virtual double getResultHorizontalFOV()
Definition: FitPanorama.h:68
virtual vigra::Rect2D getResultOptimalROI()
returns the found crop rect
void OnResetCrop(wxCommandEvent &e)
event handler to reset crop area
UIntSet getCPoutsideLimit(Panorama pano, double n, bool skipOptimisation, bool includeLineCp)
optimises the whole panorama and removes all control points with error &gt; mean+n*sigma ...
Definition: CleanCP.cpp:123
PreviewToolHelper * preview_helper
wxTextCtrl * m_ROIBottomTxt
bool Enable(bool enable=true) override
enable or disable the control
Components GetComponents()
find all connected components
Definition: ImageGraph.cpp:101
subclass for a floating frame of the dock manager
void Redraw()
Definition: GLViewer.cpp:385
SplitButton * m_alignButton
wxToggleButton * m_identify_button
const std::vector< double > & getProjectionParameters() const
Get the optional projection parameters.
void OnChange(wxCommandEvent &e)
void OnIncreaseExposure(wxSpinEvent &e)
void OnTrackChangeProjectionParam(wxScrollEvent &e)
bool UpdateOverviewMode(int newMode)
updates the mode of the overview window
wxToggleButton * m_colorpicker_togglebutton
void OnRangeCompressionIncrease(wxSpinEvent &e)
static T max(T x, T y)
Definition: svm.cpp:65
bool m_showProjectionHints
Holds transformations for Image -&gt; Pano and the other way.
void SetOptions(const HuginBase::PanoramaOptions *new_opts)
Definition: ViewState.cpp:120
void OnCreateCP(wxCommandEvent &e)
handler for creating cp in pano space
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
DragMode getDragMode()
Definition: DragTool.cpp:52
unsigned int optimize(PanoramaData &pano, const char *userScript)
optimize the images imgs, for variables optvec, using vars as start.
void OnPreviewBackgroundColorChanged(wxColourPickerEvent &e)
event handler when user changes background color
void SetViewerBackground(wxColour col)
Definition: GLViewer.cpp:485
tool for manipulation of the opengl &#39;camera&#39; properties It handles the position of the camera in 3 di...
void OnImageContextMenu(wxContextMenuEvent &e)
show context menu on image buttons
void OnDragChoice(wxCommandEvent &e)
hugin_utils::FDiff2D maxpos
Definition: Correlation.h:64
PreviewColorPickerTool * color_picker_tool
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
interface of ToolHelper for deleting control points in the pano space
wxFileHistory * GetFileHistory()
Definition: MainFrame.h:187
platform/compiler specific stuff.
void SetPreviewBackgroundColor(wxColour c)
sets the sphere background color
void updateBlendMode()
Update tools and GUI elements according to blend mode choice.
bool HasNonZeroTranslationPlaneParameters()
check, if panorama has non-zero translation plane parameters
void OnEditCPTool(wxCommandEvent &e)
event handler when starting edit cp tool
PlaneOverviewToolHelper * plane_overview_helper
HuginBase::UIntSet GetFoundCPs()
return set of found control points
PreviewEditCPTool * edit_cp_tool
The PreviewColorPickerTool allows to select a region in the panorama which should be grey...
For projections where the output range is limited, but the approximatly remaped images can extend thi...
void OnBlendChoice(wxCommandEvent &e)
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
wxTextCtrl * m_exposureTextCtrl
void OnShowEvent(wxShowEvent &e)
GuiLevel
Definition: GuiLevel.h:31
void OnAutocrop(wxCommandEvent &e)
vigra::BRGBImage image
bool needsOptimization()
true if control points or lens variables have been changed after the last optimisation ...
Definition: Panorama.h:614
std::vector< wxStaticText * > m_projParamNamesLabel
PreviewProjectionGridTool * preview_projection_grid
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition: stl_utils.h:81
update global white balance
Definition: PanoCommand.h:626
customized subclass of the dock manager, created just for the purpose to create a workaround for the ...
void KeyDown(wxKeyEvent &e)
ProjectionFormat
Projection of final panorama.
HuginBase::Panorama & m_pano
void setSrcImage(unsigned int nr, const SrcPanoImage &img)
set input image parameters
PreviewGuideTool * preview_guide_tool
Allows the user to change the yaw, pitch and roll of a connected component of images by dragging them...
Definition: DragTool.h:50
void ResetTranslationPlaneParameters()
resets all translation plane parameters to zero
virtual void panoramaChanged(HuginBase::Panorama &pano)
Notification about a Panorama change.
add multiple control points
Definition: PanoCommand.h:281
wxChoice * m_GuideChoiceProj
PreviewCameraTool * camera_tool
ImageGroupButtonEventHandler(unsigned int image_number, GLPreviewFrame *frame_in, HuginBase::Panorama *m_pano)
void OnStraighten(wxCommandEvent &e)
All variables of a source image.
Definition: SrcPanoImage.h:194
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
void SetDirtyViewport()
Definition: ViewState.h:249
static ViewState * m_view_state
Definition: GLViewer.h:72
Panorama image options.
PreviewLayoutLinesTool * m_preview_layoutLinesTool
void SetZoomLevel(const float new_zoom)
Definition: ViewState.cpp:483
vigra::Size2D getSize() const
get size of output image
static bool CheckOpenGLCanDifference()
check, if graphic card supports the necessary modes for difference tool call this procedure first...
Rotate the panorama.
Definition: PanoCommand.h:448
void UpdateGlobalWhiteBalance(double redFactor, double blueFactor)
updates the global white balance
void SetImageButtonColour(unsigned int image_nr, unsigned char red, unsigned char green, unsigned char blue)
void ResetPreviewZoom()
reset zoom level for preview window
vigra::Rect2D GetSelectedROI()
returns selected ROI
void OnClose(wxCloseEvent &e)
void SetUpContext()
Definition: GLViewer.cpp:122
struct to hold a image state for stitching
wxString Components2Str(const HuginGraph::ImageGraph::Components &comp)
Definition: huginApp.cpp:84
static T min(T x, T y)
Definition: svm.cpp:62
HuginBase::UIntSet imageDragGroup
void OnNumTransform(wxCommandEvent &e)
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition: wxutils.cpp:176
void OnAlign(wxCommandEvent &e)
Visually connect the image numbers with the image on the preview.
wxTextCtrl * m_HFOVText
wxChoice * m_OverviewModeChoice
PreviewDifferenceTool * difference_tool
void OnHideProjectionHints(wxCommandEvent &e)
event handler when user hides the infobar
void createTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
initialize pano-&gt;image transformation
void OnProjParameterReset(wxCommandEvent &e)
event handler for reset projection parameters
void TurnOffTools(std::set< Tool * > tools)
void LoadImages(int preferredLensType)
HuginBase::Panorama * m_pano
void KeyUp(wxKeyEvent &e)
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
GLPreviewFrame * frame
void OnLeave(wxMouseEvent &e)
void OnFitPano(wxCommandEvent &e)
class to work with images graphs created from a HuginBase::Panorama class it creates a graph based on...
Definition: ImageGraph.h:44