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 "base_wx/platform.h"
31 #include "PerspectiveImageCtrl.h"
32 #include "vigra/transformimage.hxx"
33 #include "nona/RemappedPanoImage.h"
34 #include "nona/ImageRemapper.h"
35 #include "base_wx/wxcms.h"
36 
37 // init some values
38 bool PerspectiveImageCtrl::Create(wxWindow* parent, wxWindowID id,
39  const wxPoint& pos,
40  const wxSize& size,
41  long style,
42  const wxString& name)
43 {
44  wxScrolledWindow::Create(parent, id, pos, size, style, name);
45  // bind event handler
46  Bind(wxEVT_SIZE, &PerspectiveImageCtrl::OnSize, this);
47  Bind(wxEVT_MOTION, &PerspectiveImageCtrl::OnMouseMove, this);
48  Bind(wxEVT_LEFT_DOWN, &PerspectiveImageCtrl::OnLeftMouseDown, this);
49  Bind(wxEVT_LEFT_UP, &PerspectiveImageCtrl::OnLeftMouseUp, this);
50  Bind(wxEVT_RIGHT_UP, &PerspectiveImageCtrl::OnRightMouseUp, this);
51  Bind(wxEVT_MIDDLE_DOWN, &PerspectiveImageCtrl::OnMiddleMouseDown, this);
52  Bind(wxEVT_MIDDLE_UP, &PerspectiveImageCtrl::OnMiddleMouseUp, this);
53  Bind(wxEVT_MOUSE_CAPTURE_LOST, &PerspectiveImageCtrl::OnCaptureLost, this);
54  Bind(wxEVT_KILL_FOCUS, &PerspectiveImageCtrl::OnKillFocus, this);
55 
56  return true;
57 }
58 
59 void PerspectiveImageCtrl::setImage(const std::string& file, ImageRotation rot)
60 {
61  if (!file.empty())
62  {
63  try
64  {
65  ImageCache::getInstance().softFlush();
66  m_img = ImageCache::getInstance().getImage(file);
67  }
68  catch (...)
69  {
70  // loading of image failed, set all to empty values
71  m_imageFilename = "";
73  m_bitmap = wxBitmap();
74  // delete the image (release shared_ptr)
75  // create an empty image.
76  m_img = ImageCache::EntryPtr(new ImageCache::Entry);
77  SetVirtualSize(100, 100);
78  Refresh(true);
79  return;
80  }
82  m_imageFilename = file;
83  m_imgRotation = rot;
84  m_showRemappedImage = false;
85  rescaleImage();
86  // create initial rectangle
87  m_rectPoints.resize(4);
88  m_rectPoints[0] = vigra::Point2D(0.25 * m_realSize.GetWidth(), 0.25 * m_realSize.GetHeight());
89  m_rectPoints[1] = vigra::Point2D(0.75 * m_realSize.GetWidth(), 0.25 * m_realSize.GetHeight());
90  m_rectPoints[2] = vigra::Point2D(0.75 * m_realSize.GetWidth(), 0.75 * m_realSize.GetHeight());
91  m_rectPoints[3] = vigra::Point2D(0.25 * m_realSize.GetWidth(), 0.75 * m_realSize.GetHeight());
92  // clear lines
93  m_lines.clear();
94  update();
95  }
96  else
97  {
99  m_bitmap = wxBitmap();
100  // delete the image (release shared_ptr)
101  // create an empty image.
102  m_img = ImageCache::EntryPtr(new ImageCache::Entry);
104  SetVirtualSize(100, 100);
105  m_lines.clear();
106  Refresh(true);
107  }
108 }
109 
111 {
112  if (newRot != m_imgRotation)
113  {
114  // image rotation changed, rotate the rectangle
115  // update flag and redraw image
116  m_imgRotation = newRot;
117  rescaleImage();
118  update();
119  };
120 }
121 
122 void PerspectiveImageCtrl::OnMouseMove(wxMouseEvent& mouse)
123 {
125  {
126  return;
127  };
129  {
130  // handle scrolling and break out
131  wxPoint viewStart = GetViewStart();
132  viewStart = viewStart - (mouse.GetPosition() - m_scrollPos);
133  Scroll(viewStart);
134  m_scrollPos = mouse.GetPosition();
135  return;
136  };
137  wxPoint mpos;
138  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &mpos.x, &mpos.y);
139  hugin_utils::FDiff2D currentPos = applyRotInv(invtransform(mpos));
140  ClipPos(currentPos);
141  switch (m_editorState)
142  {
143  case POINT_MOVING:
144  m_rectPoints[m_movingPoint] = currentPos;
145  Refresh();
146  break;
147  case SEGMENT_MOVING:
149  {
150  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
152  m_rectPoints[(m_movingPoint + 1) % 4] = m_rectPoints[(m_movingPoint + 1) % 4] + delta;
153  };
154  Refresh();
155  break;
156  case RECT_MOVING:
158  {
159  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
160  for (auto& p : m_rectPoints)
161  {
162  p = p + delta;
163  };
164  };
165  Refresh();
166  break;
167  case LINE_CREATE:
168  case LINE_POINT_MOVING:
169  if (!m_currentLine.empty())
170  {
171  m_currentLine[0].end = currentPos;
172  Refresh();
173  };
174  break;
175  case LINE_MOVING:
176  if (!m_currentLine.empty())
177  {
179  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
180  m_currentLine[0].start = m_currentLine[0].start + delta;
181  m_currentLine[0].end = m_currentLine[0].end + delta;
182  Refresh();
183  };
184  break;
185  default:
186  break;
187  }
188 }
189 
190 void PerspectiveImageCtrl::OnLeftMouseDown(wxMouseEvent& mouse)
191 {
193  {
194  return;
195  };
196  DEBUG_DEBUG("LEFT MOUSE DOWN");
197  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &m_dragStartPos.x, &m_dragStartPos.y);
200  if (!HasCapture())
201  CaptureMouse();
202  SetFocus();
203 
204  if (m_editorState == SHOW_IMAGE)
205  {
206  if (m_showRect)
207  {
208  // in rect mode
210  if (m_movingPoint != -1)
211  {
212  // click is near one point of the rectangle
214  }
215  else
216  {
218  if (m_movingPoint != -1)
219  {
220  // click is near one line of the rectangle
223  }
224  else
225  {
226  if (IsInsideRect(currentPos))
227  {
228  // click is inside the rect
231  };
232  };
233  };
234  }
235  else
236  {
237  // in lines mode
238  bool isStart = true;
239  int lineIndex = GetNearestLinePoint(currentPos, isStart);
240  if (lineIndex != -1)
241  {
242  // click is near one point
244  Line currentLine = m_lines[lineIndex];
245  if (isStart)
246  {
247  // if click is near end point, mirror point
248  // so we can move always the end point
249  currentLine.Mirror();
250  }
251  m_currentLine.push_back(currentLine);
252  m_lines.erase(m_lines.begin() + lineIndex);
253  }
254  else
255  {
256  lineIndex = GetNearestLine(currentPos);
257  if (lineIndex != -1)
258  {
259  // click was near one line
261  m_lineStartDrag = m_lines[lineIndex];
262  m_currentLine.push_back(m_lineStartDrag);
263  m_lines.erase(m_lines.begin() + lineIndex);
264  }
265  else
266  {
267  // click is far from all lines, start creating a new line
269  m_currentLine.push_back(Line(currentPos, currentPos));
270  };
271  };
272  };
273  };
274 }
275 
277 {
278  if (pos.x < -PerspectiveOffset)
279  {
280  pos.x = -PerspectiveOffset;
281  };
282  if (pos.x > m_realSize.GetWidth() + PerspectiveOffset)
283  {
284  pos.x = m_realSize.GetWidth() + PerspectiveOffset;
285  };
286  if (pos.y < -PerspectiveOffset)
287  {
288  pos.y = -PerspectiveOffset;
289  };
290  if (pos.y > m_realSize.GetHeight() + PerspectiveOffset)
291  {
292  pos.y = m_realSize.GetHeight() + PerspectiveOffset;
293  };
294 }
295 
296 void PerspectiveImageCtrl::OnLeftMouseUp(wxMouseEvent& mouse)
297 {
299  {
300  return;
301  };
302  DEBUG_DEBUG("LEFT MOUSE UP");
303  wxPoint mpos;
304  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &mpos.x, &mpos.y);
305  // limit position to valid area
306  hugin_utils::FDiff2D currentPos = applyRotInv(invtransform(mpos));
307  ClipPos(currentPos);
308  bool doUpdate = false;
309  switch (m_editorState)
310  {
311  case POINT_MOVING:
313  m_rectPoints[m_movingPoint] = currentPos;
314  doUpdate = true;
315  break;
316  case SEGMENT_MOVING:
318  {
320  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
322  m_rectPoints[(m_movingPoint + 1) % 4] = m_rectPoints[(m_movingPoint + 1) % 4] + delta;
323  };
324  doUpdate = true;
325  break;
326  case RECT_MOVING:
328  {
330  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
331  for (auto& p : m_rectPoints)
332  {
333  p = p + delta;
334  };
335  };
336  doUpdate = true;
337  break;
338  case LINE_CREATE:
339  case LINE_POINT_MOVING:
341  {
342  if (!m_currentLine.empty())
343  {
344  // update line position and add them to m_lines vector
345  m_currentLine[0].end = currentPos;
346  m_lines.push_back(m_currentLine[0]);
347  m_currentLine.clear();
348  };
349  };
350  doUpdate = true;
351  break;
352  case LINE_MOVING:
354  {
355  Line movedLine = m_lineStartDrag;
356  // update start and end position of the line
357  const hugin_utils::FDiff2D delta = currentPos - applyRotInv(invtransform(m_dragStartPos));
358  movedLine.start = movedLine.start + delta;
359  movedLine.end = movedLine.end + delta;
360  m_lines.push_back(movedLine);
361  m_currentLine.clear();
362  };
363  doUpdate = true;
364  break;
365  default:
366  break;
367  };
368  if (HasCapture())
369  {
370  ReleaseMouse();
371  };
372  if (doUpdate)
373  {
374  update();
375  };
376 }
377 
378 void PerspectiveImageCtrl::OnRightMouseUp(wxMouseEvent& mouse)
379 {
381  {
382  // do nothing when
383  // * showing remapped images
384  // * when scrolling with middle mouse button
385  // * when in rectangle mode
386  return;
387  };
388  DEBUG_DEBUG("RIGHT MOUSE UP");
389  wxPoint mpos;
390  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &mpos.x, &mpos.y);
391  hugin_utils::FDiff2D currentPos = applyRotInv(invtransform(mpos));
392  if (m_editorState == SHOW_IMAGE)
393  {
394  // check if click is near one line
395  const int lineIndex = GetNearestLine(currentPos);
396  if (lineIndex != -1)
397  {
398  // delete the found line
399  m_lines.erase(m_lines.begin() + lineIndex);
400  update();
401  };
402  };
403 }
404 
406 {
408  {
409  return;
410  };
411  switch (m_editorState)
412  {
413  case SHOW_IMAGE:
414  if (!HasCapture())
415  {
416  CaptureMouse();
417  };
418  // store the scroll rate, the scroll rate set in rescaleImage is optimized for srolling
419  // with the cursor keys, but this is too high for mouse scrolling
420  // so change the scroll rate here and restore later in OnMiddleMouseUp
421  m_middleMouseScroll = true;
422  m_scrollPos = mouse.GetPosition();
423  break;
424  default:
425  // in other case ignore the middle mouse button
426  break;
427  };
428 }
429 
430 void PerspectiveImageCtrl::OnMiddleMouseUp(wxMouseEvent& mouse)
431 {
433  {
434  return;
435  };
436  if (HasCapture())
437  {
438  ReleaseMouse();
439  };
440  m_middleMouseScroll = false;
441 }
442 
443 void PerspectiveImageCtrl::OnCaptureLost(wxMouseCaptureLostEvent& e)
444 {
445  wxFocusEvent dummy;
446  OnKillFocus(dummy);
447 };
448 
450 {
451  if (HasCapture())
452  {
453  ReleaseMouse();
454  };
455 }
456 
458 {
459  wxClientDC dc(this);
460  PrepareDC(dc);
461  OnDraw(dc);
462 }
463 
464 void PerspectiveImageCtrl::SetLineColour(wxColour newColour)
465 {
466  m_colour_selected = newColour;
467  // m_overlay.Reset();
468  update();
469 }
470 
471 void PerspectiveImageCtrl::DrawRect(wxDC& dc, const std::vector<hugin_utils::FDiff2D>& rect)
472 {
473  if (rect.size() == 4)
474  {
475  wxPoint* polygonPoints = new wxPoint[4];
476  for (unsigned int j = 0; j < 4; j++)
477  {
478  polygonPoints[j] = transform(applyRot(rect[j]));
479  };
480  dc.SetPen(wxPen(m_colour_selected, 1, wxPENSTYLE_SOLID));
481  dc.SetBrush(*wxTRANSPARENT_BRUSH);
482  dc.DrawPolygon(4, polygonPoints);
483  // draw markers at each corner
484  dc.SetBrush(wxBrush(m_colour_selected));
485  for (unsigned int j = 0; j < 4; j++)
486  {
487  dc.DrawRectangle(polygonPoints[j].x - polygonPointSize, polygonPoints[j].y - polygonPointSize,
489  };
490  delete[]polygonPoints;
491  };
492 }
493 
494 void PerspectiveImageCtrl::DrawLines(wxDC& dc, const std::vector<Line>& lines)
495 {
496  if (!lines.empty())
497  {
498  dc.SetPen(wxPen(m_colour_selected, 1, wxPENSTYLE_SOLID));
499  // dc.SetBrush(*wxTRANSPARENT_BRUSH);
500  dc.SetBrush(wxBrush(m_colour_selected));
501  for (const auto& p : lines)
502  {
503  const wxPoint start = transform(applyRot(p.start));
504  const wxPoint end = transform(applyRot(p.end));
505  dc.DrawLine(start, end);
506  // draw markers
507  dc.DrawRectangle(start.x - polygonPointSize, start.y - polygonPointSize, 2 * polygonPointSize, 2 * polygonPointSize);
508  dc.DrawRectangle(end.x - polygonPointSize, end.y - polygonPointSize, 2 * polygonPointSize, 2 * polygonPointSize);
509  };
510  };
511 }
512 
514 {
516  {
517  // draw remapped image
518  if (m_remappedImg.IsOk() && m_remappedImg.GetWidth() > 0 && m_remappedImg.GetHeight() > 0)
519  {
520  dc.DrawBitmap(m_remappedImg, 0, 0);
521  };
522  }
523  else
524  {
525  // draw original image
526  if (m_bitmap.IsOk())
527  {
528  const int offset = scale(PerspectiveOffset);
529  dc.DrawBitmap(m_bitmap, offset, offset);
530  if (m_showRect)
531  {
532  // draw user rectangle
533  DrawRect(dc, m_rectPoints);
534  }
535  else
536  {
537  // draw lines
538  DrawLines(dc, m_lines);
539  if (!m_currentLine.empty())
540  {
542  };
543  };
544  }
545  else
546  {
547  // clear the rectangle and exit
548  dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
549  dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
550  dc.Clear();
551  return;
552  };
553  };
554 }
555 
557 {
559  cp.image1Nr = index;
560  cp.x1 = p1.x;
561  cp.y1 = p1.y;
562  cp.x2 = p2.x;
563  cp.y2 = p2.y;
564  const bool rotatedImage = m_imgRotation == ROT90 || m_imgRotation == ROT270;
565  if (abs(cp.x1 - cp.x2) < abs(cp.y1 - cp.y2))
566  {
568  }
569  else
570  {
572  };
573  return cp;
574 }
575 
577 {
578  if (m_showRect != newMode)
579  {
580  m_showRect = newMode;
581  update();
582  };
583 }
584 
586 {
587  HuginBase::CPVector controlPoints;
588  if (m_showRect)
589  {
590  // create control points from rect
591  controlPoints.push_back(GetCP(index, m_rectPoints[0], m_rectPoints[1]));
592  controlPoints.push_back(GetCP(index, m_rectPoints[1], m_rectPoints[2]));
593  controlPoints.push_back(GetCP(index, m_rectPoints[2], m_rectPoints[3]));
594  controlPoints.push_back(GetCP(index, m_rectPoints[3], m_rectPoints[0]));
595  }
596  else
597  {
598  // transform lines into HuginBase::ControlPoint
599  for (const auto& p : m_lines)
600  {
601  controlPoints.push_back(GetCP(index, p.start, p.end));
602  };
603  }
604  return controlPoints;
605 }
606 
608 {
609  m_pano = pano.duplicate();
610  GenerateRemappedImage(GetClientSize().GetWidth(), GetClientSize().GetHeight());
611  m_showRemappedImage = true;
612  SetVirtualSize(GetClientSize());
613  update();
614 }
615 
617 {
618  m_lines.clear();
619  for (const auto& l : lines)
620  {
621  m_lines.push_back(Line(hugin_utils::FDiff2D(l.x1, l.y1), hugin_utils::FDiff2D(l.x2, l.y2)));
622  };
623  update();
624 }
625 
626 void PerspectiveImageCtrl::OnSize(wxSizeEvent& e)
627 {
628  // rescale m_bitmap if needed.
629  if (!m_imageFilename.empty())
630  {
631  if (m_fitToWindow)
632  {
633  setScale(0);
634  }
635  };
637  {
638  GenerateRemappedImage(e.GetSize().GetWidth(), e.GetSize().GetHeight());
639  };
640 }
641 
643 {
644  if (m_editorState == NO_IMAGE)
645  {
646  return;
647  }
648  wxImage img = imageCacheEntry2wxImage(m_img);
649  if (img.GetWidth() == 0)
650  {
651  return;
652  }
653  m_imageSize = wxSize(img.GetWidth(), img.GetHeight());
655  m_imageSize.IncBy(2 * PerspectiveOffset);
656  if (m_fitToWindow)
657  {
659  };
660 
661  //scaling image to screen size
662  if (getScaleFactor() != 1.0)
663  {
664  m_imageSize.SetWidth(scale(m_imageSize.GetWidth()));
665  m_imageSize.SetHeight(scale(m_imageSize.GetHeight()));
666  wxImageResizeQuality resizeQuality = wxIMAGE_QUALITY_NORMAL;
667  if (std::max(img.GetWidth(), img.GetHeight()) > (ULONG_MAX >> 16))
668  {
669  // wxIMAGE_QUALITY_NORMAL resizes the image with ResampleNearest
670  // this algorithm works only if image dimensions are smaller then
671  // ULONG_MAX >> 16 (actual size of unsigned long differ from system
672  // to system)
673  resizeQuality = wxIMAGE_QUALITY_BOX_AVERAGE;
674  };
675  img = img.Scale(scale(m_realSize.GetWidth()), scale(m_realSize.GetHeight()), resizeQuality);
676  }
677  else
678  {
679  //the conversion to disabled m_bitmap would work on the original cached image file
680  //therefore we need to create a copy to work on it
681  img = img.Copy();
682  };
683  //and now rotating
684  switch (m_imgRotation)
685  {
686  case ROT90:
687  img = img.Rotate90(true);
688  break;
689  case ROT180:
690  img = img.Rotate180();
691  break;
692  case ROT270:
693  img = img.Rotate90(false);
694  break;
695  default:
696  break;
697  }
698  // do color correction only if input image has icc profile or if we found a monitor profile
699  if (!m_img->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
700  {
701  HuginBase::Color::CorrectImage(img, *(m_img->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
702  };
703  m_bitmap = wxBitmap(img);
704 
706  {
707  SetVirtualSize(m_imageSize.GetHeight(), m_imageSize.GetWidth());
708  }
709  else
710  {
711  SetVirtualSize(m_imageSize.GetWidth(), m_imageSize.GetHeight());
712  };
713  SetScrollRate(1, 1);
714  // reset overlay
715  // m_overlay.Reset();
716  Refresh(true);
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 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
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 GenerateRemappedImage(const unsigned int newWidth, const unsigned int newHeight)
generates the remapped image suitable for wxBitmap
void update()
initiate redraw
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.
virtual void OnDraw(wxDC &dc) wxOVERRIDE
drawing routine
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
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