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