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 
624 void PerspectiveImageCtrl::OnSize(wxSizeEvent& e)
625 {
626  // rescale m_bitmap if needed.
627  if (!m_imageFilename.empty())
628  {
629  if (m_fitToWindow)
630  {
631  setScale(0);
632  }
633  };
635  {
636  GenerateRemappedImage(e.GetSize().GetWidth(), e.GetSize().GetHeight());
637  };
638  e.Skip();
639 }
640 
642 {
643  if (m_editorState == NO_IMAGE)
644  {
645  return;
646  }
647  wxImage img = imageCacheEntry2wxImage(m_img);
648  if (img.GetWidth() == 0)
649  {
650  return;
651  }
652  m_imageSize = wxSize(img.GetWidth(), img.GetHeight());
654  m_imageSize.IncBy(2 * PerspectiveOffset);
655  if (m_fitToWindow)
656  {
658  };
659 
660  //scaling image to screen size
661  if (getScaleFactor() != 1.0)
662  {
663  m_imageSize.SetWidth(scale(m_imageSize.GetWidth()));
664  m_imageSize.SetHeight(scale(m_imageSize.GetHeight()));
665  wxImageResizeQuality resizeQuality = wxIMAGE_QUALITY_NORMAL;
666  if (std::max(img.GetWidth(), img.GetHeight()) > (ULONG_MAX >> 16))
667  {
668  // wxIMAGE_QUALITY_NORMAL resizes the image with ResampleNearest
669  // this algorithm works only if image dimensions are smaller then
670  // ULONG_MAX >> 16 (actual size of unsigned long differ from system
671  // to system)
672  resizeQuality = wxIMAGE_QUALITY_BOX_AVERAGE;
673  };
674  img = img.Scale(scale(m_realSize.GetWidth()), scale(m_realSize.GetHeight()), resizeQuality);
675  }
676  else
677  {
678  //the conversion to disabled m_bitmap would work on the original cached image file
679  //therefore we need to create a copy to work on it
680  img = img.Copy();
681  };
682  //and now rotating
683  switch (m_imgRotation)
684  {
685  case ROT90:
686  img = img.Rotate90(true);
687  break;
688  case ROT180:
689  img = img.Rotate180();
690  break;
691  case ROT270:
692  img = img.Rotate90(false);
693  break;
694  default:
695  break;
696  }
697  // do color correction only if input image has icc profile or if we found a monitor profile
698  if (!m_img->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
699  {
700  HuginBase::Color::CorrectImage(img, *(m_img->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
701  };
702  m_bitmap = wxBitmap(img);
704  Refresh(true);
705 }
706 
708 {
710  {
711  SetVirtualSize(m_imageSize.GetHeight(), m_imageSize.GetWidth());
712  }
713  else
714  {
715  SetVirtualSize(m_imageSize.GetWidth(), m_imageSize.GetHeight());
716  };
717  SetScrollRate(1, 1);
718 }
719 
720 void PerspectiveImageCtrl::GenerateRemappedImage(const unsigned int newWidth, const unsigned int newHeight)
721 {
723  //fill options with actual size
725  const double scale = std::min((double)newWidth / opts.getROI().width(), (double)newHeight / opts.getROI().height());
726  opts.setWidth(opts.getWidth() * scale, true);
727  //now remap image
728  remapped->setPanoImage(m_pano.getSrcImage(0), opts, opts.getROI());
730  remapped->remapImage(vigra::srcImageRange(*(m_img->get8BitImage())), vigra_ext::INTERP_CUBIC, progress);
731  delete progress;
732  vigra::BRGBImage remappedImage = remapped->m_image;
733  wxImage remappedwxImage;
734  remappedwxImage.SetData((unsigned char*)remappedImage.data(), remappedImage.width(), remappedImage.height(), true);
735  // apply color profiles
736  if (!m_img->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
737  {
738  HuginBase::Color::CorrectImage(remappedwxImage, *(m_img->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
739  };
740  delete remapped;
741  m_remappedImg = wxBitmap(remappedwxImage);
742 }
743 
746 {
747  const hugin_utils::FDiff2D& r(b - a);
748  const double l = (p - a) * r / (r * r);
749  if (l >= 0.0 && l <= 1.0)
750  {
751  // check that footpoint is between both points
752  const hugin_utils::FDiff2D x = a + r * l;
753  return std::sqrt(x.squareDistance(p));
754  }
755  else
756  {
757  return DBL_MAX;
758  }
759 }
760 
762 {
763  if (m_rectPoints.size() == 4)
764  {
765  double minDist = DBL_MAX;
766  int indexMin = -1;
767  for (int i = 0; i < 4; ++i)
768  {
769  const double dist = std::sqrt(p.squareDistance(m_rectPoints[i]));
770  if (dist < minDist)
771  {
772  minDist = dist;
773  indexMin = i;
774  };
775  };
776  if (minDist * getScaleFactor() < maxSelectionDistance)
777  {
778  return indexMin;
779  };
780  };
781  return -1;
782 }
783 
785 {
786  if (m_rectPoints.size() == 4)
787  {
788  double minDist = DBL_MAX;
789  int indexMin = -1;
790  for (int i = 0; i < 4; ++i)
791  {
792  double dist = GetDistance(p, m_rectPoints[i], m_rectPoints[(i + 1) % 4]);
793  if (dist < minDist)
794  {
795  minDist = dist;
796  indexMin = i;
797  };
798  };
799  if (minDist * getScaleFactor() < maxSelectionDistance)
800  {
801  return indexMin;
802  };
803  };
804  return -1;
805 }
806 
808 {
809  std::vector<double> xpos, ypos;
810  for (const auto& p : m_rectPoints)
811  {
812  xpos.push_back(p.x);
813  ypos.push_back(p.y);
814  };
815  std::sort(xpos.begin(), xpos.end());
816  std::sort(ypos.begin(), ypos.end());
817  const unsigned int index = (xpos.size() - 1) / 2;
818  return (p.x > xpos[index] && p.x < xpos[index + 1] && p.y > ypos[index] && p.y < ypos[index + 1]) ? true : false;
819 }
820 
822 {
823  if (!m_lines.empty())
824  {
825  double minDist = DBL_MAX;
826  int minLineIndex = -1;
827  bool minLineStart = false;
828  for (int i = 0; i < m_lines.size(); ++i)
829  {
830  const double distStart = std::sqrt(p.squareDistance(m_lines[i].start));
831  const double distEnd = std::sqrt(p.squareDistance(m_lines[i].end));
832  // check if distance is shorter to start or end of line
833  if (distStart < distEnd)
834  {
835  if (distStart < minDist)
836  {
837  // distance is nearer than older one
838  minDist = distStart;
839  minLineIndex = i;
840  minLineStart = true;
841  }
842  }
843  else
844  {
845  if (distEnd < minDist)
846  {
847  // distance is nearer than older one
848  minDist = distEnd;
849  minLineIndex = i;
850  minLineStart = false;
851  }
852  };
853  };
854  if (minLineIndex != -1 && minDist < DBL_MAX)
855  {
856  if (minDist * getScaleFactor() < maxSelectionDistance)
857  {
858  // distance is smaller than threshold, return nearest point
859  isStart = minLineStart;
860  return minLineIndex;
861  };
862  };
863  };
864  return -1;
865 }
866 
868 {
869  if (!m_lines.empty())
870  {
871  double minDist = DBL_MAX;
872  int indexMin = -1;
873  for (int i = 0; i < m_lines.size(); ++i)
874  {
875  double dist = GetDistance(p, m_lines[i].start, m_lines[i].end);
876  if (dist < minDist)
877  {
878  minDist = dist;
879  indexMin = i;
880  };
881  };
882  if (minDist * getScaleFactor() < maxSelectionDistance)
883  {
884  return indexMin;
885  };
886  };
887  return -1;
888 }
889 
891 {
892  if (factor == 0)
893  {
894  m_fitToWindow = true;
896  }
897  else
898  {
899  m_fitToWindow = false;
900  }
901  DEBUG_DEBUG("new scale factor:" << factor);
902  // update if factor changed
903  if (factor != m_scaleFactor)
904  {
905  m_scaleFactor = factor;
906  // keep existing scale focussed.
907  rescaleImage();
908  }
909 }
910 
912 {
913  return m_fitToWindow ? 0 : m_scaleFactor;
914 }
915 
917 {
918  int w = size.GetWidth();
919  int h = size.GetHeight();
921  {
922  int t = w;
923  w = h;
924  h = t;
925  }
926 
927  wxSize csize = GetSize();
928  DEBUG_DEBUG("csize: " << csize.GetWidth() << "x" << csize.GetHeight() << "image: " << w << "x" << h);
929  double s1 = (double)csize.GetWidth() / w;
930  double s2 = (double)csize.GetHeight() / h;
931  DEBUG_DEBUG("s1: " << s1 << " s2:" << s2);
932  return s1 < s2 ? s1 : s2;
933 }
934 
936 {
937  return m_scaleFactor;
938 }
939 
implementation of huginApp Class
Dummy progress display, without output.
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