1 // -*- c-basic-offset: 4 -*-
2 /** @file GraphTools.cpp
3  *
4  *  @brief some helper classes for graphes
5  *
6  *  @author T. Modes
7  *
8  */
9 
10 /*  This program is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2 of the License, or (at your option) any later version.
14  *
15  *  This software is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public
21  *  License along with this software. If not, see
22  *  <http://www.gnu.org/licenses/>.
23  *
24  */
25 
26 #include "panoinc_WX.h"
27 #include "GraphTools.h"
28 #include "panotools/PanoToolsInterface.h"
29 
30 namespace wxGraphTools
31 {
IMPLEMENT_CLASS(GraphPopupWindow,wxPopupTransientWindow)32 IMPLEMENT_CLASS(GraphPopupWindow, wxPopupTransientWindow)
33 
34 GraphPopupWindow::GraphPopupWindow(wxWindow* parent, wxBitmap bitmap) : wxPopupTransientWindow(parent)
35 {
36     wxPanel* panel = new wxPanel(this);
37     m_bitmapControl = new wxStaticBitmap(panel, wxID_ANY, bitmap);
38     panel->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(GraphPopupWindow::OnLeftDown), NULL, this);
39     m_bitmapControl->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(GraphPopupWindow::OnLeftDown), NULL, this);
40     m_bitmapControl->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(GraphPopupWindow::OnRightDown), NULL, this);
41     wxBoxSizer* topsizer = new wxBoxSizer(wxHORIZONTAL);
42     topsizer->Add(m_bitmapControl);
43     panel->SetSizer(topsizer);
44     topsizer->Fit(panel);
45     topsizer->Fit(this);
46 };
47 
OnLeftDown(wxMouseEvent & e)48 void GraphPopupWindow::OnLeftDown(wxMouseEvent &e)
49 {
50     Dismiss();
51 };
52 
OnRightDown(wxMouseEvent & e)53 void GraphPopupWindow::OnRightDown(wxMouseEvent &e)
54 {
55     wxConfigBase* config = wxConfigBase::Get();
56     wxFileDialog dlg(this,
57         _("Save graph"),
58         config->Read(wxT("/actualPath"), wxT("")), wxT(""),
59         _("Bitmap (*.bmp)|*.bmp|PNG-File (*.png)|*.png"),
60         wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
61     dlg.SetDirectory(config->Read(wxT("/actualPath"), wxT("")));
62     dlg.SetFilterIndex(config->Read(wxT("/lastImageTypeIndex"), 0l));
63     if (dlg.ShowModal() == wxID_OK)
64     {
65         config->Write(wxT("/actualPath"), dlg.GetDirectory());  // remember for later
66         wxFileName filename(dlg.GetPath());
67         int imageType = dlg.GetFilterIndex();
68         config->Write(wxT("/lastImageTypeIndex"), imageType);
69         if (!filename.HasExt())
70         {
71             switch (imageType)
72             {
73                 case 1:
74                     filename.SetExt(wxT("png"));
75                     break;
76                 case 0:
77                 default:
78                     filename.SetExt(wxT("bmp"));
79                     break;
80             };
81         };
82         if (filename.FileExists())
83         {
84             int d = wxMessageBox(wxString::Format(_("File %s exists. Overwrite?"), filename.GetFullPath().c_str()),
85                 _("Save image"), wxYES_NO | wxICON_QUESTION);
86             if (d != wxYES)
87             {
88                 return;
89             }
90         }
91         switch (imageType)
92         {
93             case 1:
94                 m_bitmapControl->GetBitmap().SaveFile(filename.GetFullPath(), wxBITMAP_TYPE_PNG);
95                 break;
96             case 0:
97             default:
98                 m_bitmapControl->GetBitmap().SaveFile(filename.GetFullPath(), wxBITMAP_TYPE_BMP);
99                 break;
100         };
101     };
102 };
103 
104 /*help class to draw charts */
Graph(int graphWidth,int graphHeight,wxColour backgroundColour)105 Graph::Graph(int graphWidth, int graphHeight, wxColour backgroundColour)
106 {
107     m_width = graphWidth;
108     m_height = graphHeight;
109     //create bitmap
110     m_bitmap = new wxBitmap(m_width, m_height);
111     m_dc.SelectObject(*m_bitmap);
112     m_dc.SetBackground(wxBrush(backgroundColour));
113     m_dc.Clear();
114     //draw border
115     m_dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)));
116     m_dc.SetBrush(*wxTRANSPARENT_BRUSH);
117     m_dc.DrawRectangle(0, 0, m_width, m_height);
118     SetChartArea(0, 0, m_width, m_height);
119     SetChartDisplay(0, 0, 1, 1);
120 };
121 
122 /** destructor */
~Graph()123 Graph::~Graph()
124 {
125     m_dc.SelectObject(wxNullBitmap);
126 };
127 
128 /** set where to draw the chart on the bitmap */
SetChartArea(int left,int top,int right,int bottom)129 void Graph::SetChartArea(int left, int top, int right, int bottom)
130 {
131     m_dc.DestroyClippingRegion();
132     m_left = left;
133     m_top = top;
134     m_right = right;
135     m_bottom = bottom;
136     m_dc.SetClippingRegion(m_left - 1, m_top - 1, m_right - m_left + 2, m_bottom - m_top + 2);
137 };
138 
139 /** set the real dimension of the chart */
SetChartDisplay(double xmin,double ymin,double xmax,double ymax)140 void Graph::SetChartDisplay(double xmin, double ymin, double xmax, double ymax)
141 {
142     m_xmin = xmin;
143     m_ymin = ymin;
144     m_xmax = xmax;
145     m_ymax = ymax;
146 };
147 
148 /** draws the grid with linesX lines in x-direction and linexY lines in y-direction */
DrawGrid(size_t linesX,size_t linesY)149 void Graph::DrawGrid(size_t linesX, size_t linesY)
150 {
151     m_dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)));
152     for (size_t i = 0; i < linesX; i++)
153     {
154         int x = TransformX((double)i*(m_xmax - m_xmin) / (linesX - 1) + m_xmin);
155         m_dc.DrawLine(x, m_top, x, m_bottom);
156     };
157     for (size_t i = 0; i < linesY; i++)
158     {
159         int y = TransformY((double)i*(m_ymax - m_ymin) / (linesY - 1) + m_ymin);
160         m_dc.DrawLine(m_left, y, m_right, y);
161     };
162 };
163 
164 /** draws a line with the coordinates given in points */
DrawLine(std::vector<hugin_utils::FDiff2D> points,wxColour colour,int penWidth)165 void Graph::DrawLine(std::vector<hugin_utils::FDiff2D> points, wxColour colour, int penWidth)
166 {
167     if (points.size() < 2)
168     {
169         return;
170     };
171     wxPoint *polygonPoints = new wxPoint[points.size()];
172     for (size_t i = 0; i < points.size(); i++)
173     {
174         polygonPoints[i].x = TransformX(points[i].x);
175         polygonPoints[i].y = TransformY(points[i].y);
176     };
177     m_dc.SetPen(wxPen(colour, penWidth));
178     m_dc.DrawLines(points.size(), polygonPoints);
179     delete[]polygonPoints;
180 };
181 
GetGraph() const182 const wxBitmap Graph::GetGraph() const
183 {
184     return *m_bitmap;
185 };
186 
TransformX(double x)187 int Graph::TransformX(double x)
188 {
189     return hugin_utils::round((x - m_xmin) / (m_xmax - m_xmin)*(m_right - m_left) + m_left);
190 };
191 
TransformY(double y)192 int Graph::TransformY(double y)
193 {
194     return hugin_utils::round(m_bottom - (y - m_ymin) / (m_ymax - m_ymin)*(m_bottom - m_top));
195 };
196 
GetDistortionGraph(const HuginBase::SrcPanoImage & srcImage)197 wxBitmap GetDistortionGraph(const HuginBase::SrcPanoImage& srcImage)
198 {
199 #define NRPOINTS 100
200     HuginBase::PanoramaOptions opts;
201     opts.setHFOV(srcImage.getHFOV());
202     opts.setProjection(HuginBase::PanoramaOptions::RECTILINEAR);
203     opts.setWidth(srcImage.getWidth());
204     opts.setHeight(srcImage.getHeight());
205     HuginBase::PTools::Transform transform;
206     transform.createTransform(srcImage, opts);
207 
208     const double minLength = std::min<double>(srcImage.getWidth(), srcImage.getHeight()) / 2.0;
209     const double maxR = std::sqrt(static_cast<double>(srcImage.getWidth()*srcImage.getWidth() + srcImage.getHeight()*srcImage.getHeight())) / (2.0*minLength);
210     //draw graph
211     Graph graph(300, 200, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
212     graph.SetChartArea(10, 10, 290, 190);
213     graph.SetChartDisplay(0, -0.1, maxR, 0.1);
214     graph.DrawGrid(6, 7);
215     std::vector<hugin_utils::FDiff2D> points;
216     // draw helper lines
217     // help line at r=1
218     points.push_back(hugin_utils::FDiff2D(1, -0.1));
219     points.push_back(hugin_utils::FDiff2D(1, 0.1));
220     graph.DrawLine(points, wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT), 1);
221     points.clear();
222     // helper line at r=width/height (for landscape images), maximal radius in horizontal (or vertical) direction
223     // chart goes to r for diagonal
224     const double rMaxHorzVert = std::max<double>(srcImage.getWidth(), srcImage.getHeight()) / (2.0*minLength);
225     points.push_back(hugin_utils::FDiff2D(rMaxHorzVert, -0.1));
226     points.push_back(hugin_utils::FDiff2D(rMaxHorzVert, 0.1));
227     graph.DrawLine(points, wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT), 1);
228     points.clear();
229     // now draw distortion graph
230     double r = 0;
231     for (size_t i = 0; i < NRPOINTS; i++)
232     {
233         double x, y;
234         if (transform.transform(x, y, r*minLength, 0))
235         {
236             points.push_back(hugin_utils::FDiff2D(r, x / minLength - r));
237         };
238         r += maxR / (NRPOINTS - 1);
239     };
240     graph.DrawLine(points, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), 2);
241     // return bitmap
242     return graph.GetGraph();
243 };
244 
245 } // namespace