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