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