Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CPImageCtrl.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
27 // standard wx include
28 #include "hugin_config.h"
29 #include "panoinc_WX.h"
30 
31 // standard hugin include
32 #include "panoinc.h"
33 #include "base_wx/platform.h"
34 
35 #include <vigra/inspectimage.hxx>
36 #include <vigra/transformimage.hxx>
37 #include <vigra/basicimageview.hxx>
38 #include <functional> // std::bind
39 
40 #include "hugin/config_defaults.h"
41 #include "hugin/CPImageCtrl.h"
42 #include "base_wx/wxImageCache.h"
43 #include "hugin/CPEditorPanel.h"
44 #include "hugin/MainFrame.h"
45 #include "hugin/huginApp.h"
46 #include "base_wx/wxcms.h"
47 
49 
50 // definition of the control point event
51 
53 #if defined _WIN32 && defined Hugin_shared
54 DEFINE_LOCAL_EVENT_TYPE( EVT_CPEVENT )
55 #else
56 DEFINE_EVENT_TYPE( EVT_CPEVENT )
57 #endif
58 
60 {
61  SetEventType( EVT_CPEVENT );
62  SetEventObject( (wxWindow *) NULL );
63  mode = NONE;
64 }
65 
66 CPEvent::CPEvent(wxWindow * win, CPEventMode evt_mode)
67 {
68  SetEventType(EVT_CPEVENT);
69  SetEventObject(win);
70  mode = evt_mode;
71 }
72 
74 {
75  SetEventType( EVT_CPEVENT );
76  SetEventObject( win );
78  point = p;
79 }
80 
81 CPEvent::CPEvent(wxWindow *win, unsigned int cpNr)
82 {
83  SetEventType( EVT_CPEVENT );
84  SetEventObject( win );
86  pointNr = cpNr;
87 }
88 
89 CPEvent::CPEvent(wxWindow* win, unsigned int cpNr, const hugin_utils::FDiff2D & p)
90 {
91  SetEventType( EVT_CPEVENT );
92  SetEventObject( win );
94  pointNr = cpNr;
95  point = p;
96 }
97 
98 CPEvent::CPEvent(wxWindow* win, const hugin_utils::FDiff2D & p1, const hugin_utils::FDiff2D & p2)
99 {
100  SetEventType(EVT_CPEVENT);
101  SetEventObject(win);
104  abs(hugin_utils::roundi(p2.x-p1.x)),abs(hugin_utils::roundi(p2.y-p1.y)));
105 };
106 
107 CPEvent::CPEvent(wxWindow* win, CPEventMode evt_mode, const hugin_utils::FDiff2D & p)
108 {
109  SetEventType(EVT_CPEVENT);
110  SetEventObject(win);
111  mode = evt_mode;
112  point = p;
113 }
114 
115 CPEvent::CPEvent(wxWindow* win, CPEventMode evt_mode, const HuginBase::ControlPoint cp)
116 {
117  SetEventType(EVT_CPEVENT);
118  SetEventObject(win);
119  mode=evt_mode;
120  m_cp=cp;
121 };
122 
123 CPEvent::CPEvent(wxWindow* win, CPEventMode evt_mode, size_t cpNr, const HuginBase::ControlPoint cp)
124 {
125  SetEventType(EVT_CPEVENT);
126  SetEventObject(win);
127  mode=evt_mode;
128  pointNr=cpNr;
129  m_cp=cp;
130 };
131 
132 wxEvent * CPEvent::Clone() const
133 {
134  return new CPEvent(*this);
135 }
136 
138 {
139  m_cp=cp;
140  m_control=control;
141  m_mirrored=mirrored;
143 };
144 
145 void DisplayedControlPoint::SetColour(wxColour pointColour, wxColour textColour)
146 {
147  m_pointColour=pointColour;
148  m_textColour=textColour;
149 };
150 
151 void DisplayedControlPoint::SetLabel(wxString newLabel)
152 {
153  m_label=newLabel;
154 };
155 
157 {
158  m_control=control;
159 };
160 
161 void DrawCross(wxDC& dc, wxPoint p, int l)
162 {
163  dc.DrawLine(p + wxPoint(-l, 0),
164  p + wxPoint(-1, 0));
165  dc.DrawLine(p + wxPoint(2, 0),
166  p + wxPoint(l+1, 0));
167  dc.DrawLine(p + wxPoint(0, -l),
168  p + wxPoint(0, -1));
169  dc.DrawLine(p + wxPoint(0, 2),
170  p + wxPoint(0, l+1));
171 };
172 
173 void DisplayedControlPoint::Draw(wxDC& dc, const wxRect& visibleRect, bool selected, bool newPoint)
174 {
175  if(m_control==NULL)
176  {
177  return;
178  };
179  // select color
180  wxColour bgColor = m_pointColour;
181  wxColour textColor = m_textColour;
182  bool drawMag = false;
183  if (selected)
184  {
185  bgColor = wxTheColourDatabase->Find(wxT("RED"));
186  textColor = wxTheColourDatabase->Find(wxT("WHITE"));
188  }
189  if (newPoint)
190  {
191  bgColor = wxTheColourDatabase->Find(wxT("YELLOW"));
192  textColor = wxTheColourDatabase->Find(wxT("BLACK"));
193  drawMag = true;
194  }
195 
196  dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
197  dc.SetBrush(wxBrush(wxT("BLACK"),wxBRUSHSTYLE_TRANSPARENT));
198 
200  hugin_utils::FDiff2D point = m_control->applyRot(pointInput);
201  wxPoint p = m_control->roundP(m_control->scale(point));
202  hugin_utils::FDiff2D pointInput2;
203  wxPoint p2;
204  if(IsDrawingLine())
205  {
207  hugin_utils::FDiff2D point2 = m_control->applyRot(pointInput2);
208  p2 = m_control->roundP(m_control->scale(point2));
209  // check that line is in visible range
210  const wxRect lineRect(p, p2);
211  if (!visibleRect.Intersects(lineRect))
212  {
213  // reset label position, so it is not considered when checking
214  m_labelPos = wxRect();
215  m_labelPos2 = wxRect();
216  return;
217  };
218  }
219  else
220  {
221  // check that point is inside the visible rect
222  if (!visibleRect.Contains(p))
223  {
224  // reset label position, so it is not considered when checking
225  m_labelPos = wxRect();
226  m_labelPos2 = wxRect();
227  return;
228  };
229  }
230  int l = 6;
231  // draw cursor line, choose white or black
232  vigra::Rect2D box;
233  if(IsDrawingLine())
234  {
235  box.setUpperLeft(vigra::Point2D(hugin_utils::roundi(std::min(m_cp.x1, m_cp.x2)) - l, hugin_utils::roundi(std::min(m_cp.y1, m_cp.y2)) - l));
236  box.setSize(hugin_utils::roundi(std::abs(m_cp.x1 - m_cp.x2) + 2.0*l), hugin_utils::roundi(std::abs(m_cp.y1 - m_cp.y2) + 2.0*l));
237  }
238  else
239  {
240  box.setUpperLeft(vigra::Point2D(hugin_utils::roundi(pointInput.x - l), hugin_utils::roundi(pointInput.y - l)));
241  box.setSize(2*l, 2*l);
242  };
243  // only use part inside.
244  box &= vigra::Rect2D(m_control->GetImg()->size());
245  if(box.width()<=0 || box.height()<=0)
246  {
247  return;
248  };
249  // calculate mean "luminance value"
250  vigra::FindAverage<vigra::UInt8> average; // init functor
251  vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> > lumac;
252  vigra::inspectImage(m_control->GetImg()->upperLeft()+ box.upperLeft(),
253  m_control->GetImg()->upperLeft()+ box.lowerRight(),
254  lumac, average);
255  if (average() < 150)
256  {
257  dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
258  }
259  else
260  {
261  dc.SetPen(wxPen(wxT("BLACK"), 1, wxPENSTYLE_SOLID));
262  }
263 
264  if(IsDrawingLine())
265  {
266  DrawLine(dc);
267  DrawCross(dc, p, l);
268  DrawCross(dc, p2, l);
269  }
270  else
271  {
273  {
274  DrawLineSegment(dc);
275  };
276  DrawCross(dc, p, l);
277  };
278  // calculate distance to the image boundaries,
279  // decide where to put the label and magnifier
280  if (IsDrawingLine())
281  {
282  m_labelPos2 = DrawTextMag(dc, p2, pointInput2, drawMag, textColor, bgColor);
283  };
284  // draw first point second so that is on top
285  m_labelPos=DrawTextMag(dc, p, pointInput, drawMag, textColor, bgColor);
286 }
287 
288 wxRect DisplayedControlPoint::DrawTextMag(wxDC& dc, wxPoint p, hugin_utils::FDiff2D pointInput, bool drawMag, wxColour textColour, wxColour bgColour)
289 {
290  wxRect labelPos;
291  int l = 6;
292  wxSize clientSize = m_control->GetClientSize();
293  int vx0, vy0;
294  m_control->GetViewStart(&vx0, &vy0);
295  wxFont font(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT);
296  dc.SetFont(font);
297  wxPoint pClient(p.x - vx0, p.y - vy0);
298  // space in upper left, upper right, lower left, lower right
299  int maxDistUR = std::min(clientSize.x - pClient.x, pClient.y);
300  int maxDistLL = std::min(pClient.x, clientSize.y - pClient.y);
301  int maxDistLR = std::min(clientSize.x - pClient.x, clientSize.y - pClient.y);
302 
303  // text and magnifier offset
304  int toff = l-1;
305  // default to lower right
306  wxPoint tul = p + wxPoint(toff,toff);
307 
308  // calculate text position and extend
309  // width of border around text label
310  int tB = 2;
311  wxCoord tw, th;
312  dc.GetTextExtent(m_label, &tw, &th);
313 
314  if (drawMag && m_control->getScale() < 2)
315  {
316  const wxBitmap& magBitmap = m_control->GetMagBitmap(pointInput);
317  // TODO: select position depending on visible part of canvas
318  wxPoint ulMag = tul;
319  // choose placement of the magnifier
320  int w = toff + magBitmap.GetWidth()+3;
321  int db = 5;
322  if ( maxDistLR > w + db )
323  {
324  ulMag = p + wxPoint(toff,toff);
325  }
326  else
327  {
328  if (maxDistLL > w + db)
329  {
330  ulMag = p + wxPoint(-w, toff);
331  }
332  else
333  {
334  if (maxDistUR > w + db)
335  {
336  ulMag = p + wxPoint(toff, -w);
337  }
338  else
339  {
340  ulMag = p + wxPoint(-w, -w);
341  }
342  }
343  };
344 
345  dc.DrawBitmap(magBitmap, ulMag);
346  dc.SetPen(wxPen(wxT("BLACK"), 1, wxPENSTYLE_SOLID));
347  dc.SetBrush(wxBrush(wxT("WHITE"),wxBRUSHSTYLE_TRANSPARENT));
348 
349  // draw Bevel
350  int bw = magBitmap.GetWidth();
351  int bh = magBitmap.GetHeight();
352  dc.DrawLine(ulMag.x-1, ulMag.y+bh,
353  ulMag.x+bw+1, ulMag.y+bh);
354  dc.DrawLine(ulMag.x+bw, ulMag.y+bh,
355  ulMag.x+bw, ulMag.y-2);
356  dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
357  dc.DrawLine(ulMag.x-1, ulMag.y-1,
358  ulMag.x+bw+1, ulMag.y-1);
359  dc.DrawLine(ulMag.x-1, ulMag.y+bh,
360  ulMag.x-1, ulMag.y-2);
361  }
362  // choose placement of text.
363  int db = 5;
364  int w = toff+tw+2*tB;
365  if ( maxDistLR > w + db && (!drawMag) )
366  {
367  tul = p + wxPoint(toff,toff);
368  }
369  else
370  {
371  if (maxDistLL > w + db)
372  {
373  tul = p + wxPoint(-w, toff);
374  }
375  else
376  {
377  if (maxDistUR > w + db)
378  {
379  tul = p + wxPoint(toff, -(toff) - (th+2*tB));
380  }
381  else
382  {
383  tul = p + wxPoint(-w, -(toff) - (th+2*tB));
384  };
385  };
386  };
387 
388  // draw background
389  dc.SetPen(wxPen(textColour, 1, wxPENSTYLE_SOLID));
390  dc.SetBrush(wxBrush(bgColour, wxBRUSHSTYLE_SOLID));
391  dc.DrawRectangle(tul.x, tul.y, tw+2*tB+1, th+2*tB);
392  labelPos.SetLeft(tul.x);
393  labelPos.SetTop(tul.y);
394  labelPos.SetWidth(tw+2*tB+1);
395  labelPos.SetHeight(th+2*tB);
396  // draw number
397  dc.SetTextForeground(textColour);
398  dc.DrawText(m_label, tul + wxPoint(tB,tB));
399  return labelPos;
400 };
401 
403 {
404  if(m_control==NULL)
405  {
406  return;
407  };
408  hugin_utils::FDiff2D p1, p2, dp;
409  // transform end points to pano space
411  {
412  return;
413  };
415  {
416  return;
417  };
418  dp=p2-p1;
419  int len = hugin_utils::roundi(sqrt((m_cp.x1 - m_cp.x2)*(m_cp.x1 - m_cp.x2) + (m_cp.y1 - m_cp.y2)*(m_cp.y1 - m_cp.y2))) + 1;
420  if(len<5)
421  {
422  //very short line, draw straight line
425  }
426  else
427  {
428  //longer line, draw correct line, taking output projection into account
429  wxPoint* points=new wxPoint[len+1];
430  for(size_t i=0; i<len+1; i++)
431  {
432  hugin_utils::FDiff2D p = p1 + dp*((double)i / len);
433  // transform line coordinates back to image space
435  {
436  delete []points;
437  //fall through, draw direct line, not exact, but better than no line
440  return;
441  };
442  // check that all points are inside of image, accept a little border around the whole image
443  if (p2.x<-100 || p2.x>m_control->GetRealImageSize().GetWidth() + 100 ||
444  p2.y<-100 || p2.y>m_control->GetRealImageSize().GetHeight() + 100)
445  {
446  // this can happen, if the line cp span the 360 deg border
447  // in this case don't draw anything
448  delete[]points;
449  return;
450  }
451  points[i]=m_control->roundP(m_control->scale(m_control->applyRot(p2)));
452  };
453  dc.SetClippingRegion(wxPoint(0, 0), m_control->GetBitmapSize());
454  dc.DrawLines(len+1, points);
455  dc.DestroyClippingRegion();
456  delete []points;
457  };
458 };
459 
461 {
462  if(m_control==NULL)
463  {
464  return;
465  };
466  // calculate line equation
468  hugin_utils::FDiff2D p2_image = m_mirrored ? hugin_utils::FDiff2D(m_cp.x1, m_cp.y1) : hugin_utils::FDiff2D(m_cp.x2, m_cp.y2);
469  hugin_utils::FDiff2D p1, p2, dp;
470  if(!m_control->getFirstInvTrans()->transformImgCoord(p1, p1_image))
471  {
472  return;
473  };
474  if(!m_control->getSecondInvTrans()->transformImgCoord(p2, p2_image))
475  {
476  return;
477  };
478  dp=p2-p1;
479  // now find the parameter to draw an appropriate long line segment
480  double f=1.0;
481  int image_width=m_control->GetRealImageSize().GetWidth();
482  int image_height=m_control->GetRealImageSize().GetHeight();
483  int image_dimension=std::min(image_width, image_height);
484  int line_length=-1;
485  while(f>1e-4)
486  {
487  p2=p1+dp*f;
488  if(m_control->getFirstTrans()->transformImgCoord(p2_image, p2))
489  {
490  double length=sqrt(p1_image.squareDistance(p2_image));
491  if(length > 0.05f * image_dimension && length < 0.75f * image_dimension)
492  {
493  line_length=hugin_utils::roundi(length);
494  break;
495  };
496  };
497  f*=0.9;
498  };
499  // found no suitable length, don't draw line
500  if(line_length<1)
501  {
502  return;
503  };
504  // now calc line positions
505  wxPoint* points=new wxPoint[2*line_length+1];
506  for(size_t i=0; i<2*line_length+1; i++)
507  {
508  hugin_utils::FDiff2D p = p1 + dp*f*(((double)i - line_length) / (2.0f*line_length));
510  {
511  delete []points;
512  return;
513  };
514  points[i]=m_control->roundP(m_control->scale(m_control->applyRot(p2)));
515  };
516  //and finally draw line segment
517  dc.SetClippingRegion(wxPoint(0,0), m_control->GetBitmapSize());
518  dc.DrawLines(2*line_length+1, points);
519  dc.DestroyClippingRegion();
520  delete []points;
521 };
522 
524 {
525  return m_line && m_control->IsShowingLines();
526 }
527 
528 const bool DisplayedControlPoint::isOccupiedLabel(const wxPoint mousePos) const
529 {
530  if(IsDrawingLine())
531  {
532  return m_labelPos.Contains(mousePos) || m_labelPos2.Contains(mousePos);
533  }
534  else
535  {
536  return m_labelPos.Contains(mousePos);
537  };
538 };
539 
541 {
542  double d=m_control->invScale(3.0);
543  if(IsDrawingLine())
544  {
545  return (p.x < m_cp.x1 + d && p.x > m_cp.x1 - d && p.y < m_cp.y1 + d && p.y > m_cp.y1 - d) ||
546  (p.x < m_cp.x2 + d && p.x > m_cp.x2 - d && p.y < m_cp.y2 + d && p.y > m_cp.y2 - d);
547  }
548  else
549  {
550  if(m_mirrored)
551  {
552  return (p.x < m_cp.x2 + d && p.x > m_cp.x2 - d && p.y < m_cp.y2 + d && p.y > m_cp.y2 - d);
553  }
554  else
555  {
556  return (p.x < m_cp.x1 + d && p.x > m_cp.x1 - d && p.y < m_cp.y1 + d && p.y > m_cp.y1 - d);
557  };
558  };
559 };
560 
561 void DisplayedControlPoint::CheckSelection(const wxPoint mousePos, const hugin_utils::FDiff2D& p)
562 {
563  if(!IsDrawingLine())
564  {
565  return;
566  };
567  double d=m_control->invScale(3.0);
568  m_mirrored=m_labelPos2.Contains(mousePos) ||
569  (p.x < m_cp.x2 + d && p.x > m_cp.x2 - d && p.y < m_cp.y2 + d && p.y > m_cp.y2 - d);
570 };
571 
573 {
574  if(m_mirrored)
575  {
576  m_cp.x2=x;
577  }
578  else
579  {
580  m_cp.x1=x;
581  };
582 };
583 
585 {
586  if(m_mirrored)
587  {
588  m_cp.y2=y;
589  }
590  else
591  {
592  m_cp.y1=y;
593  };
594 };
595 
597 {
598  if(m_mirrored)
599  {
600  m_cp.x2=newPoint.x;
601  m_cp.y2=newPoint.y;
602  }
603  else
604  {
605  m_cp.x1=newPoint.x;
606  m_cp.y1=newPoint.y;
607  };
608 };
609 
611 {
612  if(m_mirrored)
613  {
614  m_cp.x2+=shift.x;
615  m_cp.y2+=shift.y;
616  }
617  else
618  {
619  m_cp.x1+=shift.x;
620  m_cp.y1+=shift.y;
621  };
622 };
623 
625 {
626  //start a new line control point
627  m_line=true;
628  m_mirrored=true;
629  m_label=_("new");
630  m_cp.image1Nr=UINT_MAX;
631  m_cp.x1=newPoint.x;
632  m_cp.y1=newPoint.y;
634  m_cp.x2=m_cp.x1;
635  m_cp.y2=m_cp.y1;
637 };
638 
640 {
642 };
643 
645 {
646  return m_cp==other.GetControlPoint() && m_mirrored == other.IsMirrored() && m_label == other.GetLabel();
647 };
648 
649 // our image control
650 BEGIN_EVENT_TABLE(CPImageCtrl, wxScrolledWindow)
651  EVT_SIZE(CPImageCtrl::OnSize)
652  EVT_CHAR(CPImageCtrl::OnKey)
653 // EVT_KEY_UP(CPImageCtrl::OnKeyUp)
654  EVT_KEY_DOWN(CPImageCtrl::OnKeyDown)
655  EVT_LEAVE_WINDOW(CPImageCtrl::OnMouseLeave)
656  EVT_ENTER_WINDOW(CPImageCtrl::OnMouseEnter)
657  EVT_MOTION(CPImageCtrl::mouseMoveEvent)
658  EVT_LEFT_DOWN(CPImageCtrl::mousePressLMBEvent)
659  EVT_LEFT_UP(CPImageCtrl::mouseReleaseLMBEvent)
660  EVT_RIGHT_DOWN(CPImageCtrl::mousePressRMBEvent)
661  EVT_RIGHT_UP(CPImageCtrl::mouseReleaseRMBEvent)
662  EVT_MIDDLE_DOWN(CPImageCtrl::mousePressMMBEvent)
663  EVT_MIDDLE_UP(CPImageCtrl::mouseReleaseMMBEvent)
664  EVT_TIMER(-1, CPImageCtrl::OnTimer)
665 #ifdef __WXMSW__
666  // update view after scrolling on Windows
667  // on WXGTK this is handled already by the control
668  EVT_SCROLLWIN(CPImageCtrl::OnScrollWin)
669 #endif
671 
672 bool CPImageCtrl::Create(wxWindow * parent, wxWindowID id,
673  const wxPoint& pos,
674  const wxSize& size,
675  long style,
676  const wxString& name)
677 {
678  wxScrolledWindow::Create(parent, id, pos, size, style, name);
679  selectedPointNr = 0;
680  editState = NO_IMAGE;
681  scaleFactor = 1;
682  fitToWindow = false;
683  m_showSearchArea = false;
684  m_searchRectWidth = 0;
685  m_showTemplateArea = false;
686  m_templateRectWidth = 0;
687  m_editPanel = 0;
688  m_imgRotation = ROT0;
689  m_sameImage = false;
690  m_magImgCenter = hugin_utils::FDiff2D(-1, -1);
691 
692  wxString filename;
693 
694 #if defined(__WXMSW__)
695  wxString cursorPath = huginApp::Get()->GetXRCPath() + wxT("/data/cursor_cp_pick.cur");
696  m_CPSelectCursor = new wxCursor(cursorPath, wxBITMAP_TYPE_CUR);
697 #else
698  m_CPSelectCursor = new wxCursor(wxCURSOR_CROSS);
699 #endif
700  SetCursor(*m_CPSelectCursor);
701 
702  // TODO: define custom, light background colors.
703  pointColors.push_back(wxTheColourDatabase->Find(wxT("BLUE")));
704  textColours.push_back(wxTheColourDatabase->Find(wxT("WHITE")));
705 
706  pointColors.push_back(wxTheColourDatabase->Find(wxT("GREEN")));
707  textColours.push_back(wxTheColourDatabase->Find(wxT("WHITE")));
708 
709  pointColors.push_back(wxTheColourDatabase->Find(wxT("CYAN")));
710  textColours.push_back(wxTheColourDatabase->Find(wxT("BLACK")));
711  pointColors.push_back(wxTheColourDatabase->Find(wxT("GOLD")));
712  textColours.push_back(wxTheColourDatabase->Find(wxT("BLACK")));
713 
714  pointColors.push_back(wxTheColourDatabase->Find(wxT("NAVY")));
715  textColours.push_back(wxTheColourDatabase->Find(wxT("WHITE")));
716 
717  pointColors.push_back(wxTheColourDatabase->Find(wxT("DARK TURQUOISE")));
718  textColours.push_back(wxTheColourDatabase->Find(wxT("BLACK")));
719 
720  pointColors.push_back(wxTheColourDatabase->Find(wxT("SALMON")));
721  textColours.push_back(wxTheColourDatabase->Find(wxT("BLACK")));
722 
723  pointColors.push_back(wxTheColourDatabase->Find(wxT("MAROON")));
724  textColours.push_back(wxTheColourDatabase->Find(wxT("BLACK")));
725 
726  pointColors.push_back(wxTheColourDatabase->Find(wxT("KHAKI")));
727  textColours.push_back(wxTheColourDatabase->Find(wxT("BLACK")));
728 
729  m_searchRectWidth = 120;
730  m_mouseInWindow = false;
731  m_forceMagnifier = false;
732  m_timer.SetOwner(this);
733 
734  return true;
735 }
736 
738 {
739  m_editPanel = parent;
740  m_sameImage = false;
742 }
743 
745 {
746  DEBUG_TRACE("dtor");
747  this->SetCursor(wxNullCursor);
748  delete m_CPSelectCursor;
749  DEBUG_TRACE("dtor end");
750 }
751 
752 void CPImageCtrl::OnDraw(wxDC & dc)
753 {
754  wxSize vSize = GetClientSize();
755  // draw image (FIXME, redraw only visible regions.)
756  if (editState != NO_IMAGE && m_img.get()) {
757  //clear the blank rectangle to the left of the image
758  if (bitmap.GetWidth() < vSize.GetWidth()) {
759  dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
760  dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
761  dc.DrawRectangle(bitmap.GetWidth(), 0,
762  vSize.GetWidth() - bitmap.GetWidth(),vSize.GetHeight());
763  }
764  //clear the blank rectangle below the image
765  if (bitmap.GetHeight() < vSize.GetHeight()) {
766  dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
767  dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
768  dc.DrawRectangle(0, bitmap.GetHeight(),
769  vSize.GetWidth(), vSize.GetHeight() - bitmap.GetHeight());
770  }
771  dc.DrawBitmap(bitmap,0,0);
772  } else {
773  // clear the rectangle and exit
774  dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
775  dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
776  dc.Clear();
777  return;
778  }
779 
780  // draw known points.
781  wxRect visibleRect(GetViewStart(), vSize);
782  visibleRect.Inflate(20);
783  for(size_t i=0; i<m_points.size(); i++)
784  {
786  {
787  m_points[i].Draw(dc, visibleRect, false);
788  };
789  }
790 
791  switch(editState) {
792  case NEW_POINT_SELECTED:
793  // Boundary check
794  if ((newPoint.x < 0) || (newPoint.y < 0)) {
795  // Tried to create a point outside of the canvas. Ignore it.
796  break;
797  }
798  {
799  DisplayedControlPoint dsp(HuginBase::ControlPoint(0, newPoint.x, newPoint.y, 0, 0, 0), this, false);
800  dsp.SetLabel(_("new"));
801  dsp.Draw(dc, visibleRect, false, true);
802  }
803  if (m_showTemplateArea) {
804  dc.SetLogicalFunction(wxINVERT);
805  dc.SetPen(wxPen(wxT("RED"), 1, wxPENSTYLE_SOLID));
806  dc.SetBrush(wxBrush(wxT("WHITE"), wxBRUSHSTYLE_TRANSPARENT));
807  wxPoint upperLeft = applyRot(roundP(newPoint));
808  upperLeft = scale(upperLeft);
809 
810  int width = scale(m_templateRectWidth);
811 
812  dc.DrawRectangle(upperLeft.x-width, upperLeft.y-width, 2*width, 2*width);
813  dc.SetLogicalFunction(wxCOPY);
814  }
815 
816  break;
817  case NEW_LINE_CREATING:
818  m_selectedPoint.Draw(dc, visibleRect, false, true);
819  break;
821  m_points[selectedPointNr].Draw(dc, visibleRect, true);
822  break;
824  case NO_SELECTION:
825  case NO_IMAGE:
826  break;
827  }
828 
829  if (m_showSearchArea && m_mousePos.x != -1){
830  dc.SetLogicalFunction(wxINVERT);
831  dc.SetPen(wxPen(wxT("WHITE"), 1, wxPENSTYLE_SOLID));
832  dc.SetBrush(wxBrush(wxT("WHITE"), wxBRUSHSTYLE_TRANSPARENT));
833 
835  upperLeft = scale(upperLeft);
836  int width = scale(m_searchRectWidth);
837  DEBUG_DEBUG("drawing rect " << upperLeft << " with width " << 2*width << " orig: " << m_searchRectWidth*2 << " scale factor: " << getScaleFactor());
838 
839  dc.DrawRectangle(hugin_utils::roundi(upperLeft.x - width), hugin_utils::roundi(upperLeft.y - width), 2 * width, 2 * width);
840  dc.SetLogicalFunction(wxCOPY);
841  }
842 }
843 
845 {
846  if (m_magImgCenter == point)
847  {
848  // if point has not moved use cached image
849  return m_magImg;
850  };
851  // point has changed, we need to recalculate the magnified image
852  typedef vigra::RGBValue<vigra::UInt8> VT;
853  DEBUG_TRACE("")
854 
855  // draw magnified image
856  // width (and height) of magnifier region (output), should be odd
857  int magWidth = wxConfigBase::Get()->Read(wxT("/CPEditorPanel/MagnifierWidth"),61l);
858  int hw = magWidth/2;
859  magWidth = hw*2+1;
860 
861  wxImage img(magWidth, magWidth);
862  vigra::BasicImageView<VT> magImg((VT*)img.GetData(), magWidth,magWidth);
863  vigra::BImage maskImg(magWidth, magWidth);
865 
866  // middle pixel
867  double mx, my;
868  m_magInvTrans->transformImgCoord(mx, my, point.x, point.y);
869 
870  // apply the transform, for the small window the multithreading has too much overhead, so use only single threaded version
873  vigra::destImageRange(magImg),
874  vigra::destImage(maskImg),
875  *m_magTrans,
876  ptf,
877  vigra::Diff2D(hugin_utils::roundi(mx - hw),
878  hugin_utils::roundi(my - hw)),
880  false,
881  &progDisp,
882  true);
883 
884  // TODO: contrast enhancement
885  vigra::FindMinMax<vigra::UInt8> minmax;
886  vigra::inspectImage(vigra::srcImageRange(magImg), minmax);
887 
888  // transform to range 0...255
890  vigra::linearRangeMapping(
891  VT(minmax.min), VT(minmax.max), // src range
892  VT(0, 0, 0), VT(255, 255, 255)) // dest range
893  );
894 // vigra::transformImage(srcImageRange(magImg), destImage(magImg),
895 // vigra::BrightnessContrastFunctor<float>(brightness, contrast, minmax.min, minmax.max));
896 
897  // draw cursor
898  for(int x=0; x < magWidth; x++) {
899  VT p =magImg(x,hw+1);
900  vigra::UInt8 v = 0.3/255*p.red() + 0.6/255*p.green() + 0.1/255*p.blue() < 0.5 ? 255 : 0;
901  p[0] = v;
902  p[1] = v;
903  p[2] = v;
904  magImg(x,hw+1) = p;
905  p = magImg(hw+1, x);
906  v = 0.3/255*p.red() + 0.6/255*p.green() + 0.1/255*p.blue() < 0.5 ? 255 : 0;
907  p[0] = v;
908  p[1] = v;
909  p[2] = v;
910  magImg(hw+1, x) = p;
911  }
912 
913  // rotate image according to current display
914  switch (m_imgRotation) {
915  case ROT90:
916  img = img.Rotate90(true);
917  break;
918  case ROT180:
919  img = img.Rotate180();
920  break;
921  case ROT270:
922  img = img.Rotate90(false);
923  break;
924  default:
925  break;
926  };
927 
928  m_magImg = wxBitmap(img);
929  m_magImgCenter = point;
930  return m_magImg;
931 }
932 
934 {
935  return wxSize(imageSize.GetWidth(),imageSize.GetHeight());
936 }
937 
938 
939 void CPImageCtrl::setImage(const std::string & file, ImageRotation imgRot)
940 {
941  DEBUG_TRACE("setting Image " << file);
942  imageFilename = file;
943  m_sameImage=false;
945  wxString fn(imageFilename.c_str(),HUGIN_CONV_FILENAME);
946  if (wxFileName::FileExists(fn)) {
947  m_imgRotation = imgRot;
948  m_img = ImageCache::getInstance().getImageIfAvailable(imageFilename);
950  if (m_img.get()) {
951  rescaleImage();
952  } else {
953  // load the image in the background.
954  m_imgRequest = ImageCache::getInstance().requestAsyncImage(imageFilename);
955  m_imgRequest->ready.push_back(
956  std::bind(&CPImageCtrl::OnImageLoaded, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
957  );
958  // With m_img.get() 0, everything will act as normal except drawing.
959  }
960  } else {
962  bitmap = wxBitmap();
963  // delete the image (release shared_ptr)
964  // create an empty image.
965  m_img = ImageCache::EntryPtr(new ImageCache::Entry);
966  }
967 }
968 
970 {
971  m_firstTrans=firstTrans;
972  m_firstInvTrans=firstInvTrans;
973  m_secondInvTrans=secondInvTrans;
974 };
975 
977 {
978  m_magTrans = magTrans;
979  m_magInvTrans = magInvTrans;
980 }
981 
982 void CPImageCtrl::setSameImage(bool sameImage)
983 {
984  m_sameImage=sameImage;
985 };
986 
987 void CPImageCtrl::OnImageLoaded(ImageCache::EntryPtr entry, std::string filename, bool load_small)
988 {
989  // check we are still displaying this image
990  if (imageFilename == filename)
991  {
992  m_img = entry;
993  rescaleImage();
994  }
995 }
996 
998 {
999  if (editState == NO_IMAGE || !m_img.get()) {
1000  return;
1001  }
1002  wxImage img = imageCacheEntry2wxImage(m_img);
1003  if (img.GetWidth() == 0) {
1004  return;
1005  }
1006  imageSize = wxSize(img.GetWidth(), img.GetHeight());
1008  if (fitToWindow) {
1010  }
1011  DEBUG_DEBUG("src image size "
1012  << imageSize.GetHeight() << "x" << imageSize.GetWidth());
1013  if (getScaleFactor() == 1.0) {
1014  //the icc correction would work on the original cached image file
1015  //therefore we need to create a copy to work on it
1016  img = img.Copy();
1017  }
1018  else
1019  {
1020  // rescale image
1021  imageSize.SetWidth(scale(imageSize.GetWidth()));
1022  imageSize.SetHeight(scale(imageSize.GetHeight()));
1023  DEBUG_DEBUG("rescaling to " << imageSize.GetWidth() << "x"
1024  << imageSize.GetHeight());
1025  wxImageResizeQuality resizeQuality = wxIMAGE_QUALITY_NORMAL;
1026  if (std::max(img.GetWidth(), img.GetHeight()) > (ULONG_MAX >> 16))
1027  {
1028  // wxIMAGE_QUALITY_NORMAL resizes the image with ResampleNearest
1029  // this algorithm works only if image dimensions are smaller then
1030  // ULONG_MAX >> 16 (actual size of unsigned long differ from system
1031  // to system)
1032  resizeQuality = wxIMAGE_QUALITY_BOX_AVERAGE;
1033  };
1034  img = img.Scale(imageSize.GetWidth(), imageSize.GetHeight(), resizeQuality);
1035  };
1036  // need to rotate full image. warning. this can be very memory intensive
1037  if (m_imgRotation != ROT0)
1038  {
1039  switch (m_imgRotation)
1040  {
1041  case ROT90:
1042  img = img.Rotate90(true);
1043  break;
1044  case ROT180:
1045  img = img.Rotate180();
1046  break;
1047  case ROT270:
1048  img = img.Rotate90(false);
1049  break;
1050  default:
1051  break;
1052  };
1053  };
1054  // do color correction only if input image has icc profile or if we found a monitor profile
1055  if (!m_img->iccProfile->empty() || huginApp::Get()->HasMonitorProfile())
1056  {
1058  };
1059  bitmap = wxBitmap(img);
1060 
1061  if (m_imgRotation == ROT90 || m_imgRotation == ROT270) {
1062  SetVirtualSize(imageSize.GetHeight(), imageSize.GetWidth());
1063  } else {
1064  SetVirtualSize(imageSize.GetWidth(), imageSize.GetHeight());
1065  }
1066  SetScrollRate(1,1);
1067  Refresh(FALSE);
1068 }
1069 
1070 void CPImageCtrl::setCtrlPoint(const HuginBase::ControlPoint& cp, const bool mirrored)
1071 {
1072  DisplayedControlPoint dcp(cp, this, mirrored);
1073  dcp.SetColour(pointColors[m_points.size() % pointColors.size()], textColours[m_points.size() % textColours.size()]);
1074  dcp.SetLabel(wxString::Format(wxT("%lu"), (unsigned long int)m_points.size()));
1075  m_points.push_back(dcp);
1076 }
1077 
1079 {
1080  m_points.clear();
1082  {
1084  };
1085  selectedPointNr = UINT_MAX;
1086 };
1087 
1089 {
1090  DEBUG_TRACE("clearNewPoint");
1091  if (editState != NO_IMAGE) {
1093  }
1094 }
1095 
1096 
1097 void CPImageCtrl::selectPoint(unsigned int nr, bool scrollTo)
1098 {
1099  DEBUG_TRACE("nr: " << nr);
1100  if (nr < m_points.size()) {
1101  selectedPointNr = nr;
1103  if (scrollTo)
1104  {
1105  // scroll to center only when requested
1106  showPosition(m_points[nr].GetPos());
1107  };
1108  update();
1109  } else {
1110  DEBUG_DEBUG("trying to select invalid point nr: " << nr << ". Nr of points: " << m_points.size());
1111  }
1112 }
1113 
1115 {
1116  DEBUG_TRACE("deselecting points");
1119  }
1120  // update view
1121  update();
1122 }
1123 
1125 {
1126  DEBUG_DEBUG("x: " << point.x << " y: " << point.y);
1127  // transform and scale the co-ordinate to the screen.
1128  point = applyRot(point);
1129  point = scale(point);
1130  int x = hugin_utils::roundi(point.x);
1131  int y = hugin_utils::roundi(point.y);
1132 
1133  wxSize sz = GetClientSize();
1134  int scrollx = x - sz.GetWidth()/2;
1135  int scrolly = y - sz.GetHeight()/2;
1136  Scroll(scrollx, scrolly);
1137  if (warpPointer) {
1138  int sx,sy;
1139  GetViewStart(&sx, &sy);
1140  DEBUG_DEBUG("relative coordinages: " << x-sx << "," << y-sy);
1141  WarpPointer(x-sx,y-sy);
1142  }
1143 }
1144 
1145 CPImageCtrl::EditorState CPImageCtrl::isOccupied(wxPoint mousePos, const hugin_utils::FDiff2D &p, unsigned int & pointNr) const
1146 {
1147  // check if mouse is hovering over a label
1148  if(!m_points.empty())
1149  {
1150  for(int i=m_points.size()-1; i>=0; i--)
1151  {
1152  if(m_points[i].isOccupiedLabel(mousePos))
1153  {
1154  pointNr = i;
1155  return KNOWN_POINT_SELECTED;
1156  }
1157  };
1158  // check if mouse is over a known point
1159  for(std::vector<DisplayedControlPoint>::const_iterator it=m_points.begin(); it!=m_points.end(); ++it)
1160  {
1161  if(it->isOccupiedPos(p))
1162  {
1163  pointNr = it - m_points.begin();
1164  return KNOWN_POINT_SELECTED;
1165  }
1166  };
1167  };
1168 
1169  return NEW_POINT_SELECTED;
1170 }
1171 
1173 {
1174  wxClientDC dc(this);
1175  PrepareDC(dc);
1176  wxDCOverlay overlaydc(m_overlay, &dc);
1177  overlaydc.Clear();
1178  dc.SetPen(wxPen(*wxWHITE, 2, wxPENSTYLE_LONG_DASH));
1179  dc.SetBrush(*wxTRANSPARENT_BRUSH);
1180  wxPoint p1=roundP(scale(applyRot(pos1)));
1181  wxPoint p2=roundP(scale(applyRot(pos2)));
1182  dc.DrawRectangle(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y);
1183 };
1184 
1185 void CPImageCtrl::mouseMoveEvent(wxMouseEvent& mouse)
1186 {
1187  if (!m_img.get()) return; // ignore events if no image loaded.
1188  wxPoint unScrolledMousePos;
1189  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
1190  &unScrolledMousePos.x, & unScrolledMousePos.y);
1191  hugin_utils::FDiff2D mpos(unScrolledMousePos.x, unScrolledMousePos.y);
1192  bool doUpdate = false;
1193  mpos = applyRotInv(invScale(mpos));
1194  // if mouseclick is out of image, ignore
1195  if ((mpos.x >= m_realSize.GetWidth() || mpos.y >= m_realSize.GetHeight()) && editState!=SELECT_DELETE_REGION)
1196  {
1197  return;
1198  }
1199 
1200 // DEBUG_DEBUG(" pos:" << mpos.x << ", " << mpos.y);
1201  // only if the shift key is not pressed.
1202  if (mouse.LeftIsDown() && ! mouse.ShiftDown()) {
1203  switch(editState) {
1204  case NO_SELECTION:
1205  DEBUG_DEBUG("mouse down movement without selection, in NO_SELECTION state!");
1206  break;
1207  case KNOWN_POINT_SELECTED:
1208  if (mpos.x >= 0 && mpos.x <= m_realSize.GetWidth()){
1209  m_points[selectedPointNr].UpdateControlPointX(mpos.x);
1210  } else if (mpos.x < 0) {
1211  m_points[selectedPointNr].UpdateControlPointX(0);
1212  } else if (mpos.x > m_realSize.GetWidth()) {
1213  m_points[selectedPointNr].UpdateControlPointX(m_realSize.GetWidth());
1214  }
1215 
1216  if (mpos.y >= 0 && mpos.y <= m_realSize.GetHeight()){
1217  m_points[selectedPointNr].UpdateControlPointY(mpos.y);
1218  } else if (mpos.y < 0) {
1219  m_points[selectedPointNr].UpdateControlPointY(0);
1220  } else if (mpos.y > m_realSize.GetHeight()) {
1221  m_points[selectedPointNr].UpdateControlPointY(m_realSize.GetHeight());
1222  }
1223  // emit a notify event here.
1224  //
1225  //emit(pointMoved(selectedPointNr, points[selectedPointNr]));
1226  // do more intelligent updating here?
1227  doUpdate = true;
1228  break;
1229  // not possible.
1230  case NEW_POINT_SELECTED:
1231  DEBUG_DEBUG("WARNING: mouse move in new point state")
1232  newPoint = mpos;
1233  doUpdate = true;
1234  break;
1235  case NEW_LINE_CREATING:
1237  doUpdate = true;
1238  break;
1239  case SELECT_DELETE_REGION:
1240  case NO_IMAGE:
1241  break;
1242  }
1243  }
1244 
1245  if ((mouse.MiddleIsDown() || mouse.ShiftDown() || mouse.m_controlDown ) && editState!=SELECT_DELETE_REGION) {
1246  // scrolling with the mouse
1247  if (m_mouseScrollPos !=mouse.GetPosition()) {
1248  wxPoint delta = mouse.GetPosition() - m_mouseScrollPos;
1249  if (mouse.MiddleIsDown())
1250  {
1251  // invert scroll direction for middle mouse click (touchpad like scrolling)
1252  delta = -delta;
1253  };
1254  // scrolling is done later
1255  if (mouse.ShiftDown()) {
1256  // emit scroll event, so that other window can be scrolled
1257  // as well.
1258  CPEvent e(this, CPEvent::SCROLLED, hugin_utils::FDiff2D(delta.x, delta.y));
1259  emit(e);
1260  } else {
1261  // scroll only our window
1262  ScrollDelta(delta);
1263  }
1264  m_mouseScrollPos = mouse.GetPosition();
1265  }
1266  }
1267 
1268  if(mouse.RightIsDown() && editState==SELECT_DELETE_REGION)
1269  {
1270  //update selection rectangle
1272  }
1273 // DEBUG_DEBUG("ImageDisplay: mouse move, state: " << editState);
1274 
1275  // draw a rectangle
1276  if (m_showSearchArea) {
1277  doUpdate = true;
1278  }
1279 
1280  unsigned int selPointNr;
1281  if (isOccupied(unScrolledMousePos, mpos, selPointNr) == KNOWN_POINT_SELECTED ) {
1282  SetCursor(wxCursor(wxCURSOR_ARROW));
1283  } else {
1284  SetCursor(*m_CPSelectCursor);
1285  }
1286 
1287  m_mousePos = mpos;
1288  // repaint
1289  if (doUpdate) {
1290  update();
1291  }
1292 }
1293 
1294 
1295 void CPImageCtrl::mousePressLMBEvent(wxMouseEvent& mouse)
1296 {
1297  DEBUG_DEBUG("LEFT MOUSE DOWN");
1298  if (!m_img.get()) return; // ignore events if no image loaded.
1299  //ignore left mouse button if selecting region with right mouse button
1301  return;
1302  wxPoint unScrolledMousePos;
1303  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
1304  &unScrolledMousePos.x, & unScrolledMousePos.y);
1305  hugin_utils::FDiff2D mpos(unScrolledMousePos.x, unScrolledMousePos.y);
1306  mpos = applyRotInv(invScale(mpos));
1307  DEBUG_DEBUG("mousePressEvent, pos:" << mpos.x
1308  << ", " << mpos.y);
1309  // if mouseclick is out of image, ignore
1310  if (mpos.x >= m_realSize.GetWidth() || mpos.y >= m_realSize.GetHeight()) {
1311  return;
1312  }
1313  unsigned int selPointNr = 0;
1314  EditorState clickState = isOccupied(unScrolledMousePos, mpos, selPointNr);
1315  if (mouse.LeftDown() && editState != NO_IMAGE
1316  && mpos.x < m_realSize.x && mpos.y < m_realSize.y)
1317  {
1318  // we can always select a new point
1319  if (clickState == KNOWN_POINT_SELECTED) {
1320  DEBUG_DEBUG("click on point: " << selPointNr);
1321  selectedPointNr = selPointNr;
1322  m_points[selectedPointNr].CheckSelection(unScrolledMousePos, mpos);
1324  editState = clickState;
1325  // notify parent and therefore other CPImageCtrl to select the clicked point
1326  CPEvent e( this, selectedPointNr);
1327  // stop timer so that magnifier is always displayed when moving cp and not hidden by timer
1328  m_timer.Stop();
1329  m_forceMagnifier = true;
1330  emit(e);
1331  } else if (clickState == NEW_POINT_SELECTED) {
1332  DEBUG_DEBUG("click on new space, select new point");
1333  if(m_sameImage && mouse.AltDown())
1334  {
1338  }
1339  else
1340  {
1342  };
1343  newPoint = mpos;
1344  } else {
1345  DEBUG_ERROR("invalid state " << clickState << " on mouse down");
1346  }
1347 // DEBUG_DEBUG("ImageDisplay: mouse down, state change: " << oldstate
1348 // << " -> " << editState);
1349  }
1350  m_mousePos = mpos;
1351 }
1352 
1353 void CPImageCtrl::OnTimer(wxTimerEvent & e)
1354 {
1355  if (!m_img.get()) return; // ignore events if no image loaded.
1356  m_forceMagnifier = false;
1357  update();
1358 }
1359 
1360 void CPImageCtrl::OnScrollWin(wxScrollWinEvent& e)
1361 {
1362  // repaint image, so that labels and magnifier are updated
1363  update();
1364  e.Skip();
1365 }
1366 
1367 void CPImageCtrl::mouseReleaseLMBEvent(wxMouseEvent& mouse)
1368 {
1369  DEBUG_DEBUG("LEFT MOUSE UP");
1370  if (!m_img.get()) return; // ignore events if no image loaded.
1371  //ignore left mouse button if selecting region with right mouse button
1373  return;
1374 
1375  m_timer.Start(2000, true);
1376 
1377  wxPoint mpos_;
1378  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
1379  &mpos_.x, & mpos_.y);
1380  hugin_utils::FDiff2D mpos(mpos_.x, mpos_.y);
1381  mpos = applyRotInv(invScale(mpos));
1382  DEBUG_DEBUG("mouseReleaseEvent, pos:" << mpos.x
1383  << ", " << mpos.y);
1384  // if mouseclick is out of image, ignore
1385  if (mpos.x >= m_realSize.GetWidth() || mpos.y >= m_realSize.GetHeight()) {
1386  return;
1387  }
1388 // EditorState oldState = editState;
1389  if (mouse.LeftUp()) {
1390  switch(editState) {
1391  case NO_SELECTION:
1392  DEBUG_DEBUG("mouse release without selection");
1393  break;
1394  case KNOWN_POINT_SELECTED:
1395  {
1396  DEBUG_DEBUG("mouse release with known point " << selectedPointNr);
1397  // scroll so that currently selected point is centered
1399  if (! (m_selectedPoint == m_points[selectedPointNr]) ) {
1400  CPEvent e( this, CPEvent::POINT_CHANGED, selectedPointNr, m_points[selectedPointNr].GetControlPoint());
1401  emit(e);
1402  }
1403  break;
1404  }
1405  case NEW_POINT_SELECTED:
1406  {
1407  DEBUG_DEBUG("new Point changed (event fire): x:" << mpos.x << " y:" << mpos.y);
1408  // fire the wxWin event
1409  CPEvent e( this, newPoint);
1410  emit(e);
1411  break;
1412  }
1413  case NEW_LINE_CREATING:
1414  {
1415  //notify parent
1417  emit(e);
1418  break;
1419  }
1420  case SELECT_DELETE_REGION:
1421  case NO_IMAGE:
1422  break;
1423 
1424  }
1425 // DEBUG_DEBUG("ImageDisplay: mouse release, state change: " << oldState
1426 // << " -> " << editState);
1427  }
1428 
1429 }
1430 
1431 
1432 void CPImageCtrl::mouseReleaseMMBEvent(wxMouseEvent& mouse)
1433 {
1434  DEBUG_DEBUG("middle mouse button released, leaving scroll mode")
1435 // SetCursor(wxCursor(wxCURSOR_BULLSEYE));
1436 }
1437 
1438 
1439 void CPImageCtrl::mousePressMMBEvent(wxMouseEvent& mouse)
1440 {
1441  DEBUG_DEBUG("middle mouse button pressed, entering scroll mode")
1442  if (!m_img.get()) return; // ignore events if no image loaded.
1443  m_mouseScrollPos = mouse.GetPosition();
1444 // SetCursor(wxCursor(wxCURSOR_HAND));
1445 }
1446 
1447 void CPImageCtrl::mousePressRMBEvent(wxMouseEvent& mouse)
1448 {
1449  //ignore event if no image loaded
1450  if(!m_img.get())
1451  return;
1452  wxPoint mpos_;
1453  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y, &mpos_.x, & mpos_.y);
1454  hugin_utils::FDiff2D mpos(mpos_.x, mpos_.y);
1455  mpos = applyRotInv(invScale(mpos));
1456  // if mouseclick is out of image, ignore
1457  if (mpos.x >= m_realSize.GetWidth() || mpos.y >= m_realSize.GetHeight())
1458  {
1459  return;
1460  }
1462  {
1463  rectStartPos=mpos;
1465  };
1466 };
1467 
1468 void CPImageCtrl::mouseReleaseRMBEvent(wxMouseEvent& mouse)
1469 {
1470  if (!m_img.get()) return; // ignore events if no image loaded.
1471  wxPoint mpos_;
1472  CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
1473  &mpos_.x, & mpos_.y);
1474  hugin_utils::FDiff2D mpos(mpos_.x, mpos_.y);
1475  mpos = applyRotInv(invScale(mpos));
1476  DEBUG_DEBUG("mouseReleaseEvent, pos:" << mpos.x
1477  << ", " << mpos.y);
1478 
1479  if (mouse.RightUp())
1480  {
1482  {
1483  // clear overlay
1484  {
1485  wxClientDC dc(this);
1486  PrepareDC(dc);
1487  wxDCOverlay overlaydc(m_overlay, &dc);
1488  overlaydc.Clear();
1489  m_overlay.Reset();
1490  };
1492  CPEvent e(this,rectStartPos,mpos);
1493  emit(e);
1494  }
1495  else
1496  {
1497  // if mouseclick is out of image, ignore
1498  if (mpos.x >= m_realSize.GetWidth() || mpos.y >= m_realSize.GetHeight()) {
1499  return;
1500  }
1501  // set right up event
1502  DEBUG_DEBUG("Emitting right click (rmb release)");
1503  CPEvent e(this, CPEvent::RIGHT_CLICK, mpos);
1504  emit(e);
1505  }
1506  }
1507 }
1508 
1510 {
1511  DEBUG_TRACE("edit state:" << editState);
1512  wxClientDC dc(this);
1513  PrepareDC(dc);
1514  OnDraw(dc);
1515 }
1516 
1518 {
1519  if ( ProcessEvent( ev ) == FALSE ) {
1520  wxLogWarning( _("Could not process event!") );
1521  return false;
1522  } else {
1523  return true;
1524  }
1525 }
1526 
1527 void CPImageCtrl::setScale(double factor)
1528 {
1529  if (factor == 0) {
1530  fitToWindow = true;
1531  factor = calcAutoScaleFactor(imageSize);
1532  } else {
1533  fitToWindow = false;
1534  }
1535  DEBUG_DEBUG("new scale factor:" << factor);
1536  // update if factor changed
1537  if (factor != scaleFactor) {
1538  scaleFactor = factor;
1539  // keep existing scale focussed.
1540  rescaleImage();
1541  }
1542 }
1543 
1545 {
1546  // TODO correctly autoscale rotated iamges
1547  int w = size.GetWidth();
1548  int h = size.GetHeight();
1549  if (m_imgRotation == ROT90 || m_imgRotation == ROT270) {
1550  int t = w;
1551  w = h;
1552  h = t;
1553  }
1554 
1555 // wxSize csize = GetClientSize();
1556  wxSize csize = GetSize();
1557  DEBUG_DEBUG("csize: " << csize.GetWidth() << "x" << csize.GetHeight() << "image: " << w << "x" << h);
1558  double s1 = (double)csize.GetWidth()/w;
1559  double s2 = (double)csize.GetHeight()/h;
1560  DEBUG_DEBUG("s1: " << s1 << " s2:" << s2);
1561  return s1 < s2 ? s1 : s2;
1562 }
1563 
1565 {
1566  return scaleFactor;
1567 }
1568 
1569 void CPImageCtrl::OnSize(wxSizeEvent &e)
1570 {
1571  DEBUG_TRACE("size: " << e.GetSize().GetWidth() << "x" << e.GetSize().GetHeight());
1572  // rescale bitmap if needed.
1573  if (imageFilename != "") {
1574  if (fitToWindow) {
1575  setScale(0);
1576  }
1577  }
1578 }
1579 
1580 void CPImageCtrl::OnKey(wxKeyEvent & e)
1581 {
1582  if (!m_img.get()) return; // ignore events if no image loaded.
1583  DEBUG_TRACE(" OnKey, key:" << e.m_keyCode);
1584  wxPoint delta(0,0);
1585  // check for cursor keys, if control is not pressed
1586  if ((!e.CmdDown()) && e.GetKeyCode() == WXK_LEFT ) delta.x = -1;
1587  if ((!e.CmdDown()) && e.GetKeyCode() == WXK_RIGHT ) delta.x = 1;
1588  if ((!e.CmdDown()) && e.GetKeyCode() == WXK_UP ) delta.y = -1;
1589  if ((!e.CmdDown()) && e.GetKeyCode() == WXK_DOWN ) delta.y = 1;
1590  if ( (delta.x != 0 || delta.y != 0 ) && (e.ShiftDown() || e.CmdDown())) {
1591  // move to the left
1592  double speed = (double) GetClientSize().GetWidth()/10;
1593  delta.x = (int) (delta.x * speed);
1594  delta.y = (int) (delta.y * speed);
1595  if (e.ShiftDown()) {
1596  // emit scroll event, so that other window can be scrolled
1597  // as well.
1598  CPEvent e(this, CPEvent::SCROLLED, hugin_utils::FDiff2D(delta.x, delta.y));
1599  emit(e);
1600  } else if (e.CmdDown()) {
1601  ScrollDelta(delta);
1602  }
1603  } else if (delta.x != 0 || delta.y != 0 ) {
1604 
1605  hugin_utils::FDiff2D shift(delta.x/3.0, delta.y/3.0);
1606  // rotate shift according to current display
1607  double t;
1608  switch (m_imgRotation) {
1609  case ROT90:
1610  t = shift.x;
1611  shift.x = shift.y;
1612  shift.y = -t;
1613  break;
1614  case ROT180:
1615  shift.x = -shift.x;
1616  shift.y = -shift.y;
1617  break;
1618  case ROT270:
1619  t = shift.x;
1620  shift.x = -shift.y;
1621  shift.y = t;
1622  default:
1623  break;
1624  }
1625  // move control point by half a pixel, if a point is selected
1626  if (editState == KNOWN_POINT_SELECTED ) {
1628  updatedCp.ShiftControlPoint(shift);
1630  emit(e);
1631  m_forceMagnifier = true;
1632  m_timer.Stop();
1633  m_timer.Start(2000, true);
1634  } else if (editState == NEW_POINT_SELECTED) {
1635  newPoint = newPoint + shift;
1636  // update display.
1637  update();
1638  }
1639 
1640  }
1641  else if (e.m_keyCode == 'a') {
1642  DEBUG_DEBUG("adding point with a key, faking right click");
1643  // faking right mouse button with "a"
1644  // set right up event
1646  emit(ev);
1647  }
1648  else if (e.m_keyCode==WXK_ESCAPE) {
1649  CPEvent ev(this, CPEvent::CANCELED);
1650  emit(ev);
1651  } else {
1652  // forward some keys...
1653  bool forward = false;
1654  switch (e.GetKeyCode())
1655  {
1656  case 'g':
1657  case '0':
1658  case '1':
1659  case '2':
1660  case 'f':
1661  case WXK_RIGHT:
1662  case WXK_LEFT:
1663  case WXK_UP:
1664  case WXK_DOWN:
1665  case WXK_DELETE:
1666  forward = true;
1667  break;
1668  default:
1669  break;
1670  }
1671 
1672  if (forward) {
1673  // dangelo: I don't understand why some keys are forwarded and others are not..
1674  // Delete is forwared under wxGTK, and g not..
1675  // wxWidgets 2.6.1 using gtk 2 doesn't set the event object
1676  // properly.. do it here by hand
1677  e.SetEventObject(this);
1678  DEBUG_DEBUG("forwarding key " << e.GetKeyCode()
1679  << " origin: id:" << e.GetId() << " obj: "
1680  << e.GetEventObject());
1681  // forward all keys to our parent
1682  //GetParent()->GetEventHandler()->ProcessEvent(e);
1683  m_editPanel->GetEventHandler()->ProcessEvent(e);
1684  } else {
1685  e.Skip();
1686  }
1687  }
1688 }
1689 
1690 void CPImageCtrl::OnKeyDown(wxKeyEvent & e)
1691 {
1692  DEBUG_TRACE("key:" << e.m_keyCode);
1693  if (!m_img.get()) return; // ignore events if no image loaded.
1694  if (e.m_keyCode == WXK_SHIFT || e.m_keyCode == WXK_CONTROL) {
1695  DEBUG_DEBUG("shift or control down, reseting scoll position");
1696  m_mouseScrollPos = e.GetPosition();
1697  }
1698  e.Skip();
1699 }
1700 
1701 void CPImageCtrl::OnMouseLeave(wxMouseEvent & e)
1702 {
1703  DEBUG_TRACE("MOUSE LEAVE");
1705  m_mouseInWindow = false;
1706  update();
1707 }
1708 
1709 void CPImageCtrl::OnMouseEnter(wxMouseEvent & e)
1710 {
1711  if (huginApp::Get()->getMainFrame()->IsActive())
1712  {
1713  DEBUG_TRACE("MOUSE Enter, setting focus");
1714  m_mouseInWindow = true;
1715  SetFocus();
1716  update();
1717  };
1718 }
1719 
1721 {
1722  // only possible if a new point is actually selected
1723  // DEBUG_ASSERT(editState == NEW_POINT_SELECTED);
1724  return newPoint;
1725 }
1726 
1728 {
1729  DEBUG_DEBUG("setting new point " << p.x << "," << p.y);
1730  // should we need to check for some precondition?
1731  newPoint = p;
1733 
1734  // show new point.
1735  showPosition(p);
1736 
1737  // we do not send an event, since CPEditorPanel
1738  // caused the change.. so it doesn't need to filter
1739  // out its own change messages.
1740 }
1741 
1743 {
1744  m_showSearchArea = show;
1745  if (show)
1746  {
1747  int templSearchAreaPercent = wxConfigBase::Get()->Read(wxT("/Finetune/SearchAreaPercent"), HUGIN_FT_SEARCH_AREA_PERCENT);
1748  m_searchRectWidth = (m_realSize.GetWidth() * templSearchAreaPercent) / 200;
1749  DEBUG_DEBUG("Setting new search area: w in %:" << templSearchAreaPercent << " bitmap width: " << bitmap.GetWidth() << " resulting size: " << m_searchRectWidth);
1751  }
1752 }
1753 
1755 {
1756  m_showTemplateArea = show;
1757  if (show)
1758  {
1759  m_templateRectWidth = wxConfigBase::Get()->Read(wxT("/Finetune/TemplateSize"),HUGIN_FT_TEMPLATE_SIZE) / 2;
1760  }
1761 }
1762 
1763 wxPoint CPImageCtrl::MaxScrollDelta(wxPoint delta)
1764 {
1765  int x,y;
1766  GetViewStart( &x, &y );
1767 
1768  wxSize winSize = GetClientSize();
1769  wxSize imgSize;
1770  imgSize.x = bitmap.GetWidth();
1771  imgSize.y = bitmap.GetHeight();
1772  // check for top and left border
1773  if (x + delta.x < 0) {
1774  delta.x = -x;
1775  }
1776  if (y + delta.y < 0) {
1777  delta.y = -y;
1778  }
1779  // check for right and bottom border
1780  int right = x + delta.x + winSize.x ;
1781  if (right > imgSize.x) {
1782  delta.x = imgSize.x - right;
1783  if (delta.x < 0) {
1784  delta.x = 0;
1785  }
1786  }
1787  int bottom = y + delta.y + winSize.y ;
1788  if (bottom > imgSize.y) {
1789  delta.y = imgSize.y - bottom;
1790  if (delta.y < 0) {
1791  delta.y = 0;
1792  }
1793  }
1794  return delta;
1795 }
1796 
1797 void CPImageCtrl::ScrollDelta(const wxPoint & delta)
1798 {
1799  // TODO: adjust
1800  if (delta.x == 0 && delta.y == 0) {
1801  return;
1802  }
1803  int x,y;
1804  GetViewStart( &x, &y );
1805  x = x + delta.x;
1806  y = y + delta.y;
1807  if (x<0) x = 0;
1808  if (y<0) y = 0;
1809  Scroll( x, y);
1810 #ifdef __WXMSW__
1811  // repaint image, so that labels and magnifier are updated
1812  // only needed on Windows, on wxGTK this is handled by the
1813  // underlying control
1814  update();
1815 #endif
1816 }
1817 
1818 const wxSize CPImageCtrl::GetBitmapSize() const
1819 {
1820  return bitmap.GetSize();
1821 };
1822 
1824 {
1825  return m_img->get8BitImage();
1826 };
1827 
1828 void CPImageCtrl::ShowLines(bool isShown)
1829 {
1830  m_showLines = isShown;
1831 }
1832 
1834 {
1835  return m_showLines;
1836 }
1837 
1838 IMPLEMENT_DYNAMIC_CLASS(CPImageCtrl, wxScrolledWindow)
1839 
1841  : wxXmlResourceHandler()
1842 {
1843  AddWindowStyles();
1844 }
1845 
1847 {
1848  XRC_MAKE_INSTANCE(cp, CPImageCtrl)
1849 
1850  cp->Create(m_parentAsWindow,
1851  GetID(),
1852  GetPosition(), GetSize(),
1853  GetStyle(wxT("style")),
1854  GetName());
1855 
1856  SetupWindow( cp);
1857 
1858  return cp;
1859 }
1860 
1862 {
1863  return IsOfClass(node, wxT("CPImageCtrl"));
1864 }
1865 
1866 IMPLEMENT_DYNAMIC_CLASS(CPImageCtrlXmlHandler, wxXmlResourceHandler)
int pointNr
Definition: CPImageCtrl.h:88
int m_templateRectWidth
Definition: CPImageCtrl.h:527
void ScrollDelta(const wxPoint &delta)
scroll the window by delta pixels
static const int NO_IMAGE
implementation of huginApp Class
bool FileExists(const std::string &filename)
checks if file exists
Definition: utils.cpp:362
CPEventMode mode
Definition: CPImageCtrl.h:82
Dummy progress display, without output.
double calcAutoScaleFactor(wxSize size)
calculate new scale factor for this image
wxColour m_pointColour
colour of the point
Definition: CPImageCtrl.h:170
HuginBase::PTools::Transform * getFirstInvTrans() const
Definition: CPImageCtrl.h:267
DisplayedControlPoint()
default constructor
Definition: CPImageCtrl.h:115
int scale(int x) const
Definition: CPImageCtrl.h:336
wxSize DoGetBestSize() const
int m_searchRectWidth
Definition: CPImageCtrl.h:521
int invScale(int x) const
Definition: CPImageCtrl.h:358
wxSize imageSize
Definition: CPImageCtrl.h:474
int roundi(T x)
Definition: hugin_math.h:73
void setNewPoint(const hugin_utils::FDiff2D &p)
set new point to a specific point
ImageRotation m_imgRotation
Definition: CPImageCtrl.h:535
void transformImage(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform an image into the panorama.
#define HUGIN_FT_SEARCH_AREA_PERCENT
hugin_utils::FDiff2D GetPos() const
returns selected position
void deselect()
remove selection.
void SetColour(wxColour pointColour, wxColour textColour)
set colours for drawing control points
void OnKeyDown(wxKeyEvent &e)
double getScaleFactor() const
get scale factor (calculates factor when fit to window is active)
ImageCache::RequestPtr m_imgRequest
Definition: CPImageCtrl.h:538
const bool GetForceMagnifier() const
Definition: CPImageCtrl.h:432
control point editor panel.
Definition: CPEditorPanel.h:64
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
bool operator==(const DisplayedControlPoint other)
compare operator
wxBitmap & GetMagBitmap(hugin_utils::FDiff2D point)
draw the magnified view of a selected control point
void Draw(wxDC &dc, const wxRect &visibleRect, bool selected, bool newPoint=false)
draw the control points to the given device context
const bool IsMirrored() const
return true, if cp is used with mirrored coordinates by current CPImageCtrl
Definition: CPImageCtrl.h:135
#define DEBUG_TRACE(msg)
Definition: utils.h:67
virtual wxEvent * Clone() const
wxBitmap bitmap
Definition: CPImageCtrl.h:471
void selectPoint(unsigned int, bool scrollTo=true)
select a point for usage
Events to notify about new point / region / point change.
Definition: CPImageCtrl.h:40
void mousePressLMBEvent(wxMouseEvent &mouse)
const cmsHPROFILE GetMonitorProfile() const
returns the monitor profile, if no monitor profile was found the sRGB profile is used instead ...
Definition: huginApp.h:151
bool m_sameImage
true, if in control point tab the same image is selected 2 times in this case a special treatment for...
Definition: CPImageCtrl.h:498
void DrawSelectionRectangle(hugin_utils::FDiff2D pos1, hugin_utils::FDiff2D pos2)
hugin_utils::FDiff2D m_magImgCenter
Definition: CPImageCtrl.h:481
bool m_forceMagnifier
Definition: CPImageCtrl.h:541
double scaleFactor
Definition: CPImageCtrl.h:517
END_EVENT_TABLE()
include file for the hugin project
bool m_showLines
Definition: CPImageCtrl.h:483
wxBitmap m_magImg
Definition: CPImageCtrl.h:480
helper class to display and manipulate cp in cp tab
Definition: CPImageCtrl.h:111
brief description.
Definition: CPImageCtrl.h:186
EditorState isOccupied(wxPoint mousePos, const hugin_utils::FDiff2D &point, unsigned int &pointNr) const
check if p is over a known point, if it is, pointNr contains the point
EditorState
state machine for selection process:
Definition: CPImageCtrl.h:237
represents a control point
Definition: ControlPoint.h:38
wxCursor * m_CPSelectCursor
Definition: CPImageCtrl.h:487
void mousePressRMBEvent(wxMouseEvent &mouse)
wxPoint m_mouseScrollPos
Definition: CPImageCtrl.h:524
void mouseMoveEvent(wxMouseEvent &mouse)
void DrawLineSegment(wxDC &dc)
draw line control point over different images
static huginApp * Get()
hack.. kind of a pseudo singleton...
Definition: huginApp.cpp:649
ImageCache::EntryPtr m_img
Definition: CPImageCtrl.h:537
const wxSize GetRealImageSize() const
return the real size of the image in the control
Definition: CPImageCtrl.h:438
bool m_mirrored
is first or second image in cp used
Definition: CPImageCtrl.h:166
cubic interpolation
void OnImageLoaded(ImageCache::EntryPtr entry, std::string filename, bool load_small)
~CPImageCtrl()
dtor.
HuginBase::ImageCache::ImageCacheRGB8Ptr GetImg()
get pointer to image, for DisplayedControlPoint
void SetControl(CPImageCtrl *control)
remember the control, where the information should be drawn
void UpdateControlPointY(double y)
update y coordinate of selected cp coordinate
const bool isOccupiedLabel(const wxPoint mousePos) const
check if given point is over label of cp, using screen coordinates
const bool GetMouseInWindow() const
Definition: CPImageCtrl.h:431
void mouseReleaseLMBEvent(wxMouseEvent &mouse)
std::vector< DisplayedControlPoint > m_points
Definition: CPImageCtrl.h:485
void clearNewPoint()
clear new point
std::string imageFilename
Definition: CPImageCtrl.h:472
void OnMouseLeave(wxMouseEvent &e)
double getScale()
return scale factor, 0 for autoscale
Definition: CPImageCtrl.h:306
bool m_showTemplateArea
Definition: CPImageCtrl.h:526
CPImageCtrl * m_control
pointer to control to access some functions
Definition: CPImageCtrl.h:168
void CheckSelection(const wxPoint mousePos, const hugin_utils::FDiff2D &p)
used by manipulating line control points, remember if the selected point given in screen coordinates ...
#define HUGIN_FT_TEMPLATE_SIZE
virtual void OnDraw(wxDC &dc)
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
void Init(CPEditorPanel *parent)
void clearCtrlPointList()
clear internal control point list
HuginBase::PTools::Transform * m_firstInvTrans
Definition: CPImageCtrl.h:508
std::shared_ptr< vigra::BRGBImage > ImageCacheRGB8Ptr
use reference counted pointers
Definition: ImageCache.h:57
std::vector< wxColour > pointColors
Definition: CPImageCtrl.h:515
virtual wxObject * DoCreateResource()
void ShiftControlPoint(hugin_utils::FDiff2D shift)
shift selected cp coordinate by given
wxImage imageCacheEntry2wxImage(ImageCache::EntryPtr e)
HuginBase::PTools::Transform * getSecondInvTrans() const
Definition: CPImageCtrl.h:268
void rescaleImage()
T applyRot(const T &p) const
Definition: CPImageCtrl.h:388
void showTemplateArea(bool show=true)
wxPoint MaxScrollDelta(wxPoint delta)
calculate maximum delta that is allowed when scrolling
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
void OnMouseEnter(wxMouseEvent &e)
bool HasMonitorProfile() const
return true if we found a suitable monitor profile and could loading it
Definition: huginApp.h:156
wxRect m_labelPos
position of the point labels (in screen coordinates)
Definition: CPImageCtrl.h:176
evaluate x, points are on a vertical line
Definition: ControlPoint.h:47
IMPEX double h[25][1024]
Definition: emor.cpp:169
void DrawCross(wxDC &dc, wxPoint p, int l)
hugin_utils::FDiff2D rectStartPos
Definition: CPImageCtrl.h:501
void update()
initiate redraw
const wxString GetLabel() const
return label
Definition: CPImageCtrl.h:137
TDiff2D< double > FDiff2D
Definition: hugin_math.h:150
void transformImageIntern(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, TRANSFORM &transform, PixelTransform &pixelTransform, vigra::Diff2D destUL, Interpolator interp, bool warparound, AppBase::ProgressDisplay *progress, bool singleThreaded)
Transform an image into the panorama.
wxRect region
Definition: CPImageCtrl.h:85
wxTimer m_timer
Definition: CPImageCtrl.h:542
void mouseReleaseRMBEvent(wxMouseEvent &mouse)
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
T applyRotInv(const T &p) const
Definition: CPImageCtrl.h:412
#define shift
Contains functions to transform whole images.
#define DEBUG_ERROR(msg)
Definition: utils.h:76
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 setTransforms(HuginBase::PTools::Transform *firstTrans, HuginBase::PTools::Transform *firstInvTrans, HuginBase::PTools::Transform *secondInvTrans)
void showSearchArea(bool show=true)
show/hide the search area rectangle
const wxSize GetBitmapSize() const
return the size of the drawn bitmap (possible rotate is applied)
wxSize m_realSize
Definition: CPImageCtrl.h:476
const HuginBase::ControlPoint GetControlPoint() const
returns the control point
Definition: CPImageCtrl.h:151
wxColour m_textColour
colour of the text background
Definition: CPImageCtrl.h:172
HuginBase::PTools::Transform * m_magTrans
Definition: CPImageCtrl.h:511
bool m_mouseInWindow
Definition: CPImageCtrl.h:540
HuginBase::ControlPoint m_cp
Definition: CPImageCtrl.h:87
void OnKey(wxKeyEvent &e)
hugin_utils::FDiff2D getNewPoint()
get the new point
void OnSize(wxSizeEvent &e)
HuginBase::PTools::Transform * m_magInvTrans
Definition: CPImageCtrl.h:512
void DrawLine(wxDC &dc)
draw line control point on same image
include file for the hugin project
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
std::vector< wxColour > textColours
Definition: CPImageCtrl.h:516
HuginBase::PTools::Transform * m_secondInvTrans
Definition: CPImageCtrl.h:509
virtual bool CanHandle(wxXmlNode *node)
bool fitToWindow
Definition: CPImageCtrl.h:518
void StartLineControlPoint(hugin_utils::FDiff2D newPoint)
starts a new line control point with given coodinates
static T max(T x, T y)
Definition: svm.cpp:65
Holds transformations for Image -&gt; Pano and the other way.
bool IsDrawingLine() const
return true, if line cp should be drawn as separate line
bool emit(CPEvent &ev)
helper func to emit a region
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
HuginBase::ControlPoint m_cp
representation of underlying control point
Definition: CPImageCtrl.h:164
void setCtrlPoint(const HuginBase::ControlPoint &cp, const bool mirrored)
add control piont to internal cp list
wxRect DrawTextMag(wxDC &dc, wxPoint p, hugin_utils::FDiff2D pointInput, bool drawMag, wxColour pointColour, wxColour textColour)
draw magnified area
const bool isOccupiedPos(const hugin_utils::FDiff2D &p) const
check if the given point is over the drawn cp, using image coordinates
hugin_utils::FDiff2D newPoint
Definition: CPImageCtrl.h:494
void mousePressMMBEvent(wxMouseEvent &mouse)
void setScale(double factor)
set the scaling factor for cp display.
vigra::triple< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImageRange(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:312
EditorState editState
Definition: CPImageCtrl.h:505
void OnTimer(wxTimerEvent &e)
void setImage(const std::string &filename, ImageRotation rot)
display img.
#define EVT_CPEVENT(func)
Definition: CPImageCtrl.h:101
void setMagTransforms(HuginBase::PTools::Transform *magTrans, HuginBase::PTools::Transform *magInvTrans)
void showPosition(hugin_utils::FDiff2D point, bool warpPointer=false)
Show point x, y.
DisplayedControlPoint m_selectedPoint
Definition: CPImageCtrl.h:493
CPEditorPanel * m_editPanel
Definition: CPImageCtrl.h:533
wxOverlay m_overlay
Definition: CPImageCtrl.h:478
void setSameImage(bool sameImage)
void OnScrollWin(wxScrollWinEvent &e)
const wxString & GetXRCPath()
return the current xrc path
Definition: huginApp.h:134
bool m_line
true, if line control point on same image
Definition: CPImageCtrl.h:179
hugin_utils::FDiff2D point
Definition: CPImageCtrl.h:86
HuginBase::PTools::Transform * getFirstTrans() const
Definition: CPImageCtrl.h:266
wxPoint roundP(const hugin_utils::FDiff2D &p) const
Definition: CPImageCtrl.h:380
void UpdateControlPoint(hugin_utils::FDiff2D newPoint)
update selected cp coordinate
void UpdateControlPointX(double x)
update x coordinate of selected cp coordinate
void mouseReleaseMMBEvent(wxMouseEvent &mouse)
bool m_showSearchArea
Definition: CPImageCtrl.h:520
static T min(T x, T y)
Definition: svm.cpp:62
bool IsShowingLines() const
ImageRotation
image rotation.
Definition: CPImageCtrl.h:258
wxString m_label
label of displayed control point: number or new
Definition: CPImageCtrl.h:174
unsigned int selectedPointNr
Definition: CPImageCtrl.h:491
hugin_utils::FDiff2D m_mousePos
Definition: CPImageCtrl.h:523
T squareDistance(TDiff2D< T > other) const
Return square of the distance to another point.
Definition: hugin_math.h:135
void ShowLines(bool isShown)
HuginBase::PTools::Transform * m_firstTrans
Definition: CPImageCtrl.h:507
void SetLabel(wxString newLabel)
set label to given wxString