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