Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PerspectiveImageCtrl.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
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 
27 #include "panoinc_WX.h"
28 #include "panoinc.h"
29 #include "ToolboxApp.h"
30 #include <wx/dcbuffer.h>
31 #include "base_wx/platform.h"
32 #include "PerspectiveImageCtrl.h"
33 #include "vigra/transformimage.hxx"
34 #include "nona/RemappedPanoImage.h"
35 #include "nona/ImageRemapper.h"
36 #include "base_wx/wxcms.h"
37 
38 // init some values
39 bool PerspectiveImageCtrl::Create(wxWindow* parent, wxWindowID id,
40  const wxPoint& pos,
41  const wxSize& size,
42  long style,
43  const wxString& name)
44 {
45  wxScrolledWindow::Create(parent, id, pos, size, style, name);
46  SetBackgroundStyle(wxBG_STYLE_PAINT);
47  // bind event handler
48  Bind(wxEVT_SIZE, &PerspectiveImageCtrl::OnSize, this);
49  Bind(wxEVT_MOTION, &PerspectiveImageCtrl::OnMouseMove, this);
50  Bind(wxEVT_LEFT_DOWN, &PerspectiveImageCtrl::OnLeftMouseDown, this);
51  Bind(wxEVT_LEFT_UP, &PerspectiveImageCtrl::OnLeftMouseUp, this);
52  Bind(wxEVT_RIGHT_UP, &PerspectiveImageCtrl::OnRightMouseUp, this);
53  Bind(wxEVT_MIDDLE_DOWN, &PerspectiveImageCtrl::OnMiddleMouseDown, this);
54  Bind(wxEVT_MIDDLE_UP, &PerspectiveImageCtrl::OnMiddleMouseUp, this);
55  Bind(wxEVT_MOUSE_CAPTURE_LOST, &PerspectiveImageCtrl::OnCaptureLost, this);
56  Bind(wxEVT_KILL_FOCUS, &PerspectiveImageCtrl::OnKillFocus, this);
57  Bind(wxEVT_PAINT, &PerspectiveImageCtrl::OnPaint, this);
58 
59  return true;
60 }
61 
62 void PerspectiveImageCtrl::setImage(const std::string& file, ImageRotation rot)
63 {
64  if (!file.empty())
65  {
66  try
67  {
68  ImageCache::getInstance().softFlush();
69  m_img = ImageCache::getInstance().getImage(file);
70  }
71  catch (...)
72  {
73  // loading of image failed, set all to empty values
74  m_imageFilename = "";
76  m_bitmap = wxBitmap();
77  // delete the image (release shared_ptr)
78  // create an empty image.
79  m_img = ImageCache::EntryPtr(new ImageCache::Entry);
80  SetVirtualSize(100, 100);
81  Refresh(true);
82  return;
83  }
85  m_imageFilename = file;
86  m_imgRotation = rot;
87  m_showRemappedImage = false;
88  rescaleImage();
89  // create initial rectangle
90  m_rectPoints.resize(4);
91  m_rectPoints[0] = vigra::Point2D(0.25 * m_realSize.GetWidth(), 0.25 * m_realSize.GetHeight());
92  m_rectPoints[1] = vigra::Point2D(0.75 * m_realSize.GetWidth(), 0.25 * m_realSize.GetHeight());
93  m_rectPoints[2] = vigra::Point2D(0.75 * m_realSize.GetWidth(), 0.75 * m_realSize.GetHeight());
94  m_rectPoints[3] = vigra::Point2D(0.25 * m_realSize.GetWidth(), 0.75 * m_realSize.GetHeight());
95  // clear lines
96  m_lines.clear();
97  Refresh();
98  }
99  else
100  {
102  m_bitmap = wxBitmap();
103  // delete the image (release shared_ptr)
104  // create an empty image.
105  m_img = ImageCache::EntryPtr(new ImageCache::Entry);
107  SetVirtualSize(100, 100);
108  m_lines.clear();
109  Refresh(true);
110  }
111 }
112 
114 {
115  if (newRot != m_imgRotation)
116  {
117  // image rotation changed, rotate the rectangle
118  // update flag and redraw image
119  m_imgRotation = newRot;
120  rescaleImage();
121  Refresh();
122  };
123 }
124 
125 void PerspectiveImageCtrl::OnMouseMove(wxMouseEvent& mouse)
126 {
128  {
129  return;
130  };
132  {
133  // handle scrolling and break out
134  wxPoint viewStart = GetViewStart();
135  viewStart = viewStart - (mouse.GetPosition() - m_scrollPos);
136  Scroll(viewStart);
137  m_scrollPos = mouse.GetPosition();
138  return;
139  };
140  wxPoint mpos;
141  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &mpos.x, &mpos.y);
142  hugin_utils::FDiff2D currentPos = applyRotInv(invtransform(mpos));
143  ClipPos(currentPos);
144  switch (m_editorState)
145  {
146  case POINT_MOVING:
147  m_rectPoints[m_movingPoint] = currentPos;
148  Refresh(false);
149  break;
150  case SEGMENT_MOVING:
152  {
153  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
155  m_rectPoints[(m_movingPoint + 1) % 4] = m_rectPoints[(m_movingPoint + 1) % 4] + delta;
156  };
157  Refresh(false);
158  break;
159  case RECT_MOVING:
161  {
162  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
163  for (auto& p : m_rectPoints)
164  {
165  p = p + delta;
166  };
167  };
168  Refresh(false);
169  break;
170  case LINE_CREATE:
171  case LINE_POINT_MOVING:
172  if (!m_currentLine.empty())
173  {
174  m_currentLine[0].end = currentPos;
175  Refresh(false);
176  };
177  break;
178  case LINE_MOVING:
179  if (!m_currentLine.empty())
180  {
182  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
183  m_currentLine[0].start = m_currentLine[0].start + delta;
184  m_currentLine[0].end = m_currentLine[0].end + delta;
185  Refresh(false);
186  };
187  break;
188  default:
189  break;
190  }
191 }
192 
193 void PerspectiveImageCtrl::OnLeftMouseDown(wxMouseEvent& mouse)
194 {
196  {
197  return;
198  };
199  DEBUG_DEBUG("LEFT MOUSE DOWN");
200  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &m_dragStartPos.x, &m_dragStartPos.y);
203  if (!HasCapture())
204  CaptureMouse();
205  SetFocus();
206 
207  if (m_editorState == SHOW_IMAGE)
208  {
209  if (m_showRect)
210  {
211  // in rect mode
213  if (m_movingPoint != -1)
214  {
215  // click is near one point of the rectangle
217  }
218  else
219  {
221  if (m_movingPoint != -1)
222  {
223  // click is near one line of the rectangle
226  }
227  else
228  {
229  if (IsInsideRect(currentPos))
230  {
231  // click is inside the rect
234  };
235  };
236  };
237  }
238  else
239  {
240  // in lines mode
241  bool isStart = true;
242  int lineIndex = GetNearestLinePoint(currentPos, isStart);
243  if (lineIndex != -1)
244  {
245  // click is near one point
247  Line currentLine = m_lines[lineIndex];
248  if (isStart)
249  {
250  // if click is near end point, mirror point
251  // so we can move always the end point
252  currentLine.Mirror();
253  }
254  m_currentLine.push_back(currentLine);
255  m_lines.erase(m_lines.begin() + lineIndex);
256  }
257  else
258  {
259  lineIndex = GetNearestLine(currentPos);
260  if (lineIndex != -1)
261  {
262  // click was near one line
264  m_lineStartDrag = m_lines[lineIndex];
265  m_currentLine.push_back(m_lineStartDrag);
266  m_lines.erase(m_lines.begin() + lineIndex);
267  }
268  else
269  {
270  // click is far from all lines, start creating a new line
272  m_currentLine.push_back(Line(currentPos, currentPos));
273  };
274  };
275  };
276  };
277 }
278 
280 {
281  if (pos.x < -PerspectiveOffset)
282  {
283  pos.x = -PerspectiveOffset;
284  };
285  if (pos.x > m_realSize.GetWidth() + PerspectiveOffset)
286  {
287  pos.x = m_realSize.GetWidth() + PerspectiveOffset;
288  };
289  if (pos.y < -PerspectiveOffset)
290  {
291  pos.y = -PerspectiveOffset;
292  };
293  if (pos.y > m_realSize.GetHeight() + PerspectiveOffset)
294  {
295  pos.y = m_realSize.GetHeight() + PerspectiveOffset;
296  };
297 }
298 
299 void PerspectiveImageCtrl::OnLeftMouseUp(wxMouseEvent& mouse)
300 {
302  {
303  return;
304  };
305  DEBUG_DEBUG("LEFT MOUSE UP");
306  wxPoint mpos;
307  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &mpos.x, &mpos.y);
308  // limit position to valid area
309  hugin_utils::FDiff2D currentPos = applyRotInv(invtransform(mpos));
310  ClipPos(currentPos);
311  bool doUpdate = false;
312  switch (m_editorState)
313  {
314  case POINT_MOVING:
316  m_rectPoints[m_movingPoint] = currentPos;
317  doUpdate = true;
318  break;
319  case SEGMENT_MOVING:
321  {
323  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
325  m_rectPoints[(m_movingPoint + 1) % 4] = m_rectPoints[(m_movingPoint + 1) % 4] + delta;
326  };
327  doUpdate = true;
328  break;
329  case RECT_MOVING:
331  {
333  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
334  for (auto& p : m_rectPoints)
335  {
336  p = p + delta;
337  };
338  };
339  doUpdate = true;
340  break;
341  case LINE_CREATE:
342  case LINE_POINT_MOVING:
344  {
345  if (!m_currentLine.empty())
346  {
347  // update line position and add them to m_lines vector
348  m_currentLine[0].end = currentPos;
349  m_lines.push_back(m_currentLine[0]);
350  m_currentLine.clear();
351  };
352  };
353  doUpdate = true;
354  break;
355  case LINE_MOVING:
357  {
358  Line movedLine = m_lineStartDrag;
359  // update start and end position of the line
360  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
361  movedLine.start = movedLine.start + delta;
362  movedLine.end = movedLine.end + delta;
363  m_lines.push_back(movedLine);
364  m_currentLine.clear();
365  };
366  doUpdate = true;
367  break;
368  default:
369  break;
370  };
371  if (HasCapture())
372  {
373  ReleaseMouse();
374  };
375  if (doUpdate)
376  {
377  Refresh(false);
378  };
379 }
380 
381 void PerspectiveImageCtrl::OnRightMouseUp(wxMouseEvent& mouse)
382 {
384  {
385  // do nothing when
386  // * showing remapped images
387  // * when scrolling with middle mouse button
388  // * when in rectangle mode
389  return;
390  };
391  DEBUG_DEBUG("RIGHT MOUSE UP");
392  wxPoint mpos;
393  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &mpos.x, &mpos.y);
394  hugin_utils::FDiff2D currentPos = applyRotInv(invtransform(mpos));
395  if (m_editorState == SHOW_IMAGE)
396  {
397  // check if click is near one line
398  const int lineIndex = GetNearestLine(currentPos);
399  if (lineIndex != -1)
400  {
401  // delete the found line
402  m_lines.erase(m_lines.begin() + lineIndex);
403  Refresh();
404  };
405  };
406 }
407 
409 {
411  {
412  return;
413  };
414  switch (m_editorState)
415  {
416  case SHOW_IMAGE:
417  if (!HasCapture())
418  {
419  CaptureMouse();
420  };
421  // store the scroll rate, the scroll rate set in rescaleImage is optimized for srolling
422  // with the cursor keys, but this is too high for mouse scrolling
423  // so change the scroll rate here and restore later in OnMiddleMouseUp
424  m_middleMouseScroll = true;
425  m_scrollPos = mouse.GetPosition();
426  break;
427  default:
428  // in other case ignore the middle mouse button
429  break;
430  };
431 }
432 
433 void PerspectiveImageCtrl::OnMiddleMouseUp(wxMouseEvent& mouse)
434 {
436  {
437  return;
438  };
439  if (HasCapture())
440  {
441  ReleaseMouse();
442  };
443  m_middleMouseScroll = false;
444 }
445 
446 void PerspectiveImageCtrl::OnCaptureLost(wxMouseCaptureLostEvent& e)
447 {
448  wxFocusEvent dummy;
449  OnKillFocus(dummy);
450 };
451 
453 {
454  if (HasCapture())
455  {
456  ReleaseMouse();
457  };
458 }
459 
460 void PerspectiveImageCtrl::SetLineColour(wxColour newColour)
461 {
462  m_colour_selected = newColour;
463  Refresh();
464 }
465 
466 void PerspectiveImageCtrl::DrawRect(wxDC& dc, const std::vector<hugin_utils::FDiff2D>& rect)
467 {
468  if (rect.size() == 4)
469  {
470  wxPoint* polygonPoints = new wxPoint[4];
471  for (unsigned int j = 0; j < 4; j++)
472  {
473  polygonPoints[j] = transform(applyRot(rect[j]));
474  };
475  dc.SetPen(wxPen(m_colour_selected, 1, wxPENSTYLE_SOLID));
476  dc.SetBrush(*wxTRANSPARENT_BRUSH);
477  dc.DrawPolygon(4, polygonPoints);
478  // draw markers at each corner
479  dc.SetBrush(wxBrush(m_colour_selected));
480  for (unsigned int j = 0; j < 4; j++)
481  {
482  dc.DrawRectangle(polygonPoints[j].x - polygonPointSize, polygonPoints[j].y - polygonPointSize,
484  };
485  delete[]polygonPoints;
486  };
487 }
488 
489 void PerspectiveImageCtrl::DrawLines(wxDC& dc, const std::vector<Line>& lines)
490 {
491  if (!lines.empty())
492  {
493  dc.SetPen(wxPen(m_colour_selected, 1, wxPENSTYLE_SOLID));
494  // dc.SetBrush(*wxTRANSPARENT_BRUSH);
495  dc.SetBrush(wxBrush(m_colour_selected));
496  for (const auto& p : lines)
497  {
498  const wxPoint start = transform(applyRot(p.start));
499  const wxPoint end = transform(applyRot(p.end));
500  dc.DrawLine(start, end);
501  // draw markers
502  dc.DrawRectangle(start.x - polygonPointSize, start.y - polygonPointSize, 2 * polygonPointSize, 2 * polygonPointSize);
503  dc.DrawRectangle(end.x - polygonPointSize, end.y - polygonPointSize, 2 * polygonPointSize, 2 * polygonPointSize);
504  };
505  };
506 }
507 
508 void PerspectiveImageCtrl::OnPaint(wxPaintEvent& e)
509 {
510  wxAutoBufferedPaintDC dc(this);
511  PrepareDC(dc);
512  dc.SetBackground(GetBackgroundColour());
513  dc.Clear();
515  {
516  // draw remapped image
517  if (m_remappedImg.IsOk() && m_remappedImg.GetWidth() > 0 && m_remappedImg.GetHeight() > 0)
518  {
519  dc.DrawBitmap(m_remappedImg, 0, 0);
520  };
521  }
522  else
523  {
524  // draw original image
525  if (m_bitmap.IsOk())
526  {
527  const int offset = scale(PerspectiveOffset);
528  dc.DrawBitmap(m_bitmap, offset, offset);
529  if (m_showRect)
530  {
531  // draw user rectangle
532  DrawRect(dc, m_rectPoints);
533  }
534  else
535  {
536  // draw lines
537  DrawLines(dc, m_lines);
538  if (!m_currentLine.empty())
539  {
541  };
542  };
543  };
544  };
545 }
546 
548 {
550  cp.image1Nr = index;
551  cp.x1 = p1.x;
552  cp.y1 = p1.y;
553  cp.x2 = p2.x;
554  cp.y2 = p2.y;
555  const bool rotatedImage = m_imgRotation == ROT90 || m_imgRotation == ROT270;
556  if (abs(cp.x1 - cp.x2) < abs(cp.y1 - cp.y2))
557  {
559  }
560  else
561  {
563  };
564  return cp;
565 }
566 
568 {
569  if (m_showRect != newMode)
570  {
571  m_showRect = newMode;
572  Refresh();
573  };
574 }
575 
577 {
578  HuginBase::CPVector controlPoints;
579  if (m_showRect)
580  {
581  // create control points from rect
582  controlPoints.push_back(GetCP(index, m_rectPoints[0], m_rectPoints[1]));
583  controlPoints.push_back(GetCP(index, m_rectPoints[1], m_rectPoints[2]));
584  controlPoints.push_back(GetCP(index, m_rectPoints[2], m_rectPoints[3]));
585  controlPoints.push_back(GetCP(index, m_rectPoints[3], m_rectPoints[0]));
586  }
587  else
588  {
589  // transform lines into HuginBase::ControlPoint
590  for (const auto& p : m_lines)
591  {
592  controlPoints.push_back(GetCP(index, p.start, p.end));
593  };
594  }
595  return controlPoints;
596 }
597 
599 {
600  m_pano = pano.duplicate();
601  GenerateRemappedImage(GetClientSize().GetWidth(), GetClientSize().GetHeight());
602  m_showRemappedImage = true;
603  SetVirtualSize(GetClientSize());
604  Refresh();
605 }
606 
608 {
609  m_showRemappedImage = false;
611  Refresh();
612 }
613 
615 {
616  m_lines.clear();
617  for (const auto& l : lines)
618  {
619  m_lines.push_back(Line(hugin_utils::FDiff2D(l.x1, l.y1), hugin_utils::FDiff2D(l.x2, l.y2)));
620  };
621  Refresh();
622 }
623 
625 {
626  m_lines.clear();
627  Refresh();
628 }
629 
630 void PerspectiveImageCtrl::OnSize(wxSizeEvent& e)
631 {
632  // rescale m_bitmap if needed.
633  if (!m_imageFilename.empty())
634  {
635  if (m_fitToWindow)
636  {
637  setScale(0);
638  }
639  };
641  {
642  GenerateRemappedImage(e.GetSize().GetWidth(), e.GetSize().GetHeight());
643  };
644  e.Skip();
645 }
646 
648 {
649  if (m_editorState == NO_IMAGE)
650  {
651  return;
652  }
653  wxImage img = imageCacheEntry2wxImage(m_img);
654  if (img.GetWidth() == 0)
655  {
656  return;
657  }
658  m_imageSize = wxSize(img.GetWidth(), img.GetHeight());
660  m_imageSize.IncBy(2 * PerspectiveOffset);
661  if (m_fitToWindow)
662  {
664  };
665 
666  //scaling image to screen size
667  if (getScaleFactor() != 1.0)
668  {
669  m_imageSize.SetWidth(scale(m_imageSize.GetWidth()));
670  m_imageSize.SetHeight(scale(m_imageSize.GetHeight()));
671  wxImageResizeQuality resizeQuality = wxIMAGE_QUALITY_NORMAL;
672  if (std::max(img.GetWidth(), img.GetHeight()) > (ULONG_MAX >> 16))
673  {
674  // wxIMAGE_QUALITY_NORMAL resizes the image with ResampleNearest
675  // this algorithm works only if image dimensions are smaller then
676  // ULONG_MAX >> 16 (actual size of unsigned long differ from system
677  // to system)
678  resizeQuality = wxIMAGE_QUALITY_BOX_AVERAGE;
679  };
680  img = img.Scale(scale(m_realSize.GetWidth()), scale(m_realSize.GetHeight()), resizeQuality);
681  }
682  else
683  {
684  //the conversion to disabled m_bitmap would work on the original cached image file
685  //therefore we need to create a copy to work on it
686  img = img.Copy();
687  };
688  //and now rotating
689  switch (m_imgRotation)
690  {
691  case ROT90:
692  img = img.Rotate90(true);
693  break;
694  case ROT180:
695  img = img.Rotate180();
696  break;
697  case ROT270:
698  img = img.Rotate90(false);
699  break;
700  default:
701  break;
702  }
703  // do color correction only if input image has icc profile or if we found a monitor profile
704  if (!m_img->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
705  {
706  HuginBase::Color::CorrectImage(img, *(m_img->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
707  };
708  m_bitmap = wxBitmap(img);
710  Refresh(true);
711 }
712 
714 {
716  {
717  SetVirtualSize(m_imageSize.GetHeight(), m_imageSize.GetWidth());
718  }
719  else
720  {
721  SetVirtualSize(m_imageSize.GetWidth(), m_imageSize.GetHeight());
722  };
723  SetScrollRate(1, 1);
724 }
725 
726 void PerspectiveImageCtrl::GenerateRemappedImage(const unsigned int newWidth, const unsigned int newHeight)
727 {
729  //fill options with actual size
731  const double scale = std::min((double)newWidth / opts.getROI().width(), (double)newHeight / opts.getROI().height());
732  opts.setWidth(opts.getWidth() * scale, true);
733  //now remap image
734  remapped->setPanoImage(m_pano.getSrcImage(0), opts, opts.getROI());
736  remapped->remapImage(vigra::srcImageRange(*(m_img->get8BitImage())), vigra_ext::INTERP_CUBIC, progress);
737  delete progress;
738  vigra::BRGBImage remappedImage = remapped->m_image;
739  wxImage remappedwxImage;
740  remappedwxImage.SetData((unsigned char*)remappedImage.data(), remappedImage.width(), remappedImage.height(), true);
741  // apply color profiles
742  if (!m_img->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
743  {
744  HuginBase::Color::CorrectImage(remappedwxImage, *(m_img->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
745  };
746  delete remapped;
747  m_remappedImg = wxBitmap(remappedwxImage);
748 }
749 
752 {
753  const hugin_utils::FDiff2D& r(b - a);
754  const double l = (p - a) * r / (r * r);
755  if (l >= 0.0 && l <= 1.0)
756  {
757  // check that footpoint is between both points
758  const hugin_utils::FDiff2D x = a + r * l;
759  return std::sqrt(x.squareDistance(p));
760  }
761  else
762  {
763  return DBL_MAX;
764  }
765 }
766 
768 {
769  if (m_rectPoints.size() == 4)
770  {
771  double minDist = DBL_MAX;
772  int indexMin = -1;
773  for (int i = 0; i < 4; ++i)
774  {
775  const double dist = std::sqrt(p.squareDistance(m_rectPoints[i]));
776  if (dist < minDist)
777  {
778  minDist = dist;
779  indexMin = i;
780  };
781  };
782  if (minDist * getScaleFactor() < maxSelectionDistance)
783  {
784  return indexMin;
785  };
786  };
787  return -1;
788 }
789 
791 {
792  if (m_rectPoints.size() == 4)
793  {
794  double minDist = DBL_MAX;
795  int indexMin = -1;
796  for (int i = 0; i < 4; ++i)
797  {
798  double dist = GetDistance(p, m_rectPoints[i], m_rectPoints[(i + 1) % 4]);
799  if (dist < minDist)
800  {
801  minDist = dist;
802  indexMin = i;
803  };
804  };
805  if (minDist * getScaleFactor() < maxSelectionDistance)
806  {
807  return indexMin;
808  };
809  };
810  return -1;
811 }
812 
814 {
815  std::vector<double> xpos, ypos;
816  for (const auto& p : m_rectPoints)
817  {
818  xpos.push_back(p.x);
819  ypos.push_back(p.y);
820  };
821  std::sort(xpos.begin(), xpos.end());
822  std::sort(ypos.begin(), ypos.end());
823  const unsigned int index = (xpos.size() - 1) / 2;
824  return (p.x > xpos[index] && p.x < xpos[index + 1] && p.y > ypos[index] && p.y < ypos[index + 1]) ? true : false;
825 }
826 
828 {
829  if (!m_lines.empty())
830  {
831  double minDist = DBL_MAX;
832  int minLineIndex = -1;
833  bool minLineStart = false;
834  for (int i = 0; i < m_lines.size(); ++i)
835  {
836  const double distStart = std::sqrt(p.squareDistance(m_lines[i].start));
837  const double distEnd = std::sqrt(p.squareDistance(m_lines[i].end));
838  // check if distance is shorter to start or end of line
839  if (distStart < distEnd)
840  {
841  if (distStart < minDist)
842  {
843  // distance is nearer than older one
844  minDist = distStart;
845  minLineIndex = i;
846  minLineStart = true;
847  }
848  }
849  else
850  {
851  if (distEnd < minDist)
852  {
853  // distance is nearer than older one
854  minDist = distEnd;
855  minLineIndex = i;
856  minLineStart = false;
857  }
858  };
859  };
860  if (minLineIndex != -1 && minDist < DBL_MAX)
861  {
862  if (minDist * getScaleFactor() < maxSelectionDistance)
863  {
864  // distance is smaller than threshold, return nearest point
865  isStart = minLineStart;
866  return minLineIndex;
867  };
868  };
869  };
870  return -1;
871 }
872 
874 {
875  if (!m_lines.empty())
876  {
877  double minDist = DBL_MAX;
878  int indexMin = -1;
879  for (int i = 0; i < m_lines.size(); ++i)
880  {
881  double dist = GetDistance(p, m_lines[i].start, m_lines[i].end);
882  if (dist < minDist)
883  {
884  minDist = dist;
885  indexMin = i;
886  };
887  };
888  if (minDist * getScaleFactor() < maxSelectionDistance)
889  {
890  return indexMin;
891  };
892  };
893  return -1;
894 }
895 
897 {
898  if (factor == 0)
899  {
900  m_fitToWindow = true;
902  }
903  else
904  {
905  m_fitToWindow = false;
906  }
907  DEBUG_DEBUG("new scale factor:" << factor);
908  // update if factor changed
909  if (factor != m_scaleFactor)
910  {
911  m_scaleFactor = factor;
912  // keep existing scale focussed.
913  rescaleImage();
914  }
915 }
916 
918 {
919  return m_fitToWindow ? 0 : m_scaleFactor;
920 }
921 
923 {
924  int w = size.GetWidth();
925  int h = size.GetHeight();
927  {
928  int t = w;
929  w = h;
930  h = t;
931  }
932 
933  wxSize csize = GetSize();
934  DEBUG_DEBUG("csize: " << csize.GetWidth() << "x" << csize.GetHeight() << "image: " << w << "x" << h);
935  double s1 = (double)csize.GetWidth() / w;
936  double s2 = (double)csize.GetHeight() / h;
937  DEBUG_DEBUG("s1: " << s1 << " s2:" << s2);
938  return s1 < s2 ? s1 : s2;
939 }
940 
942 {
943  return m_scaleFactor;
944 }
945 
implementation of huginApp Class
Dummy progress display, without output.
void RemoveLines()
remove all lines from the list
void rescaleImage()
rescale the image
ImageCache::EntryPtr m_img
image cache entry for current image
void OnRightMouseUp(wxMouseEvent &mouse)
event handler when right mouse button is released
void setPanoImage(const SrcPanoImage &src, const PanoramaOptions &dest, vigra::Rect2D roi)
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
double GetDistance(const hugin_utils::FDiff2D &p, const hugin_utils::FDiff2D &a, const hugin_utils::FDiff2D &b)
returns distance between point p and line between points a and p, the footpoint of p has to be betwee...
void OnSize(wxSizeEvent &e)
handler called when size of control was changed
void ChangeRotation(ImageRotation newRot)
Contains functions to transform whole images.
std::vector< hugin_utils::FDiff2D > m_rectPoints
include file for the hugin project
int GetNearestLine(const hugin_utils::FDiff2D &p)
return index of nearest line or -1 if the point is too far from all lines
void setScale(double factor)
set the scaling factor for mask editing display.
void SetRectMode(bool newMode)
set line or rect mode
T applyRot(const T &p) const
declaration of preview for lens calibration gui
void OnMiddleMouseDown(wxMouseEvent &mouse)
event handler for middle mouse button, start scrolling
represents a control point
Definition: ControlPoint.h:38
double calcAutoScaleFactor(wxSize size)
calculate new scale factor for this image
void GetMonitorProfile(wxString &profileName, cmsHPROFILE &profile)
Definition: wxcms.cpp:195
void DrawRect(wxDC &dc, const std::vector< hugin_utils::FDiff2D > &rect)
void ClipPos(hugin_utils::FDiff2D &pos)
clip the given pos to image size + offset
void OnPaint(wxPaintEvent &e)
drawing routine
void OnMouseMove(wxMouseEvent &mouse)
event handler when mouse is moving
Panorama duplicate() const
duplicate the panorama
Definition: Panorama.cpp:1653
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name="panel")
creates the control
double getScaleFactor() const
get scale factor (calculates factor when fit to window is active)
HuginBase::ControlPoint GetCP(const unsigned int index, const hugin_utils::FDiff2D &p1, const hugin_utils::FDiff2D &p2)
return the HuginBase::ControlPoint, using index as image index, p1 and p2 as position, take image rotation into account to decide if control point is horizontal or vertical
void setImage(const std::string &filename, ImageRotation rot)
set the current image and mask list, this loads also the image from cache
void SetRemappedMode(const HuginBase::Panorama &pano)
set the panorama object for remapping, the mouse handler are deactivated
const vigra::Rect2D & getROI() const
int GetNearestRectanglePoint(const hugin_utils::FDiff2D &p)
return index of nearest rectangle point or -1 if the point is too far from rectangle ...
Model for a panorama.
Definition: Panorama.h:152
void AddLines(const HuginBase::CPVector &lines)
add the lines to the list
const int polygonPointSize
half size of markers
int scale(int x) const
helper function for scale, offset and rotation
void CorrectImage(wxImage &image, const vigra::ImageImportInfo::ICCProfile &iccProfile, const cmsHPROFILE &monitorProfile)
apply color correction to given image using input iccProfile and monitor profile
Definition: wxcms.cpp:218
const int PerspectiveOffset
size of border at all sides
void DrawLines(wxDC &dc, const std::vector< Line > &lines)
HuginBase::CPVector GetControlPoints(const unsigned int index)
return list of control points
wxImage imageCacheEntry2wxImage(ImageCache::EntryPtr e)
void remapImage(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra_ext::Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
remap a image without alpha channel
void SetLineColour(wxColour newColour)
sets the colour for the lines
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
int transform(int x) const
convert image coordinate to screen coordinates, considers additional added border ...
evaluate x, points are on a vertical line
Definition: ControlPoint.h:47
IMPEX double h[25][1024]
Definition: emor.cpp:169
std::vector< Line > m_lines
image previewer for perspective correction
T applyRotInv(const T &p) const
PerspectiveEditorState m_editorState
void OnLeftMouseDown(wxMouseEvent &mouse)
event handler when left mouse button is pressed
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
Definition: ROIImage.h:287
void OnLeftMouseUp(wxMouseEvent &mouse)
event handler when right mouse button is released
bool IsInsideRect(const hugin_utils::FDiff2D &p)
return true, if the point p is inside the rect
void setOriginalMode()
show the original images with selected zoom ration, the mouse handlers are activated ...
void GenerateRemappedImage(const unsigned int newWidth, const unsigned int newHeight)
generates the remapped image suitable for wxBitmap
int invtransform(int x) const
translate screen coordinates to image coordinates, considers additional added border ...
void OnCaptureLost(wxMouseCaptureLostEvent &e)
event handler, when mouse capture is lost, e.g.
unsigned int getWidth() const
ImageRotation
image rotation.
include file for the hugin project
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
int GetNearestRectangleLine(const hugin_utils::FDiff2D &p)
return index of nearest rectangle line or -1 if the point is too far from the rectangle lines ...
std::vector< Line > m_currentLine
static T max(T x, T y)
Definition: svm.cpp:65
void OnMiddleMouseUp(wxMouseEvent &mouse)
event handler for middle mouse button, end scrolling
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
const int maxSelectionDistance
maximal distance for selection of one point
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
std::vector< hugin_utils::FDiff2D > m_rectPointsStartDrag
void OnKillFocus(wxFocusEvent &e)
event handler, when editor lost focus, mainly cancels creating new polygon
Panorama image options.
evaluate y, points are on a horizontal line
Definition: ControlPoint.h:48
struct to hold a image state for stitching
static T min(T x, T y)
Definition: svm.cpp:62
void UpdateVirtualSize()
update the virtual size of the control, necessary for correctly display the scrollbars ...
HuginBase::Panorama m_pano
HuginBase::Panorama object for calculation of remapped image.
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
wxBitmap m_remappedImg
the remapped image as wxBitmap
T squareDistance(TDiff2D< T > other) const
Return square of the distance to another point.
Definition: hugin_math.h:147
double getScale() const
return scale factor, 0 for autoscale
int GetNearestLinePoint(const hugin_utils::FDiff2D &p, bool &isStart)
return index of nearest line or -1 if the point to far from line