1 /*
2 * star_profile.cpp
3 * PHD Guiding
4 *
5 * Created by Sylvain Girard
6 * Copyright (c) 2013 Sylvain Girard
7 * All rights reserved.
8 *
9 * This source code is distributed under the following "BSD" license
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * Neither the name of Bret McKee, Dad Dog Development Ltd, nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 *
34 */
35
36 #include "phd.h"
37
38 BEGIN_EVENT_TABLE(ProfileWindow, wxWindow)
39 EVT_PAINT(ProfileWindow::OnPaint)
40 EVT_LEFT_DOWN(ProfileWindow::OnLClick)
41 END_EVENT_TABLE()
42
43 enum
44 {
45 HALFW = 10,
46 FULLW = 2 * HALFW + 1,
47 };
48
ProfileWindow(wxWindow * parent)49 ProfileWindow::ProfileWindow(wxWindow *parent) :
50 wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize, wxFULL_REPAINT_ON_RESIZE,_("Profile"))
51 {
52 SetBackgroundStyle(wxBG_STYLE_PAINT);
53
54 this->visible = false;
55 this->mode = 0; // 2D profile
56 this->SetBackgroundStyle(wxBG_STYLE_CUSTOM);
57 this->data = new unsigned short[FULLW * FULLW]; // 21x21 subframe
58 }
59
~ProfileWindow()60 ProfileWindow::~ProfileWindow()
61 {
62 delete[] data;
63 }
64
OnLClick(wxMouseEvent & WXUNUSED (mevent))65 void ProfileWindow::OnLClick(wxMouseEvent& WXUNUSED(mevent))
66 {
67 this->mode = this->mode + 1;
68 if (this->mode > 2) this->mode = 0;
69 Refresh();
70 }
71
SetState(bool is_active)72 void ProfileWindow::SetState(bool is_active)
73 {
74 this->visible = is_active;
75 if (is_active)
76 Refresh();
77 }
78
UpdateData(const usImage * img,float xpos,float ypos)79 void ProfileWindow::UpdateData(const usImage *img, float xpos, float ypos)
80 {
81 if (this->data == NULL) return;
82 int xstart = ROUNDF(xpos) - HALFW;
83 int ystart = ROUNDF(ypos) - HALFW;
84 if (xstart < 0) xstart = 0;
85 else if (xstart > (img->Size.GetWidth() - (FULLW + 1)))
86 xstart = img->Size.GetWidth() - (FULLW + 1);
87 if (ystart < 0) ystart = 0;
88 else if (ystart > (img->Size.GetHeight() - (FULLW + 1)))
89 ystart = img->Size.GetHeight() - (FULLW + 1);
90
91 int x,y;
92 unsigned short *uptr = this->data;
93 const int xrowsize = img->Size.GetWidth();
94 for (x = 0; x < FULLW; x++)
95 horiz_profile[x] = vert_profile[x] = midrow_profile[x] = 0;
96 for (y = 0; y < FULLW; y++) {
97 for (x = 0; x < FULLW; x++, uptr++) {
98 *uptr = *(img->ImageData + xstart + x + (ystart + y) * xrowsize);
99 horiz_profile[x] += (int) *uptr;
100 vert_profile[y] += (int) *uptr;
101 }
102 }
103 uptr = this->data + (FULLW * HALFW);
104 for (x = 0; x < FULLW; x++, uptr++)
105 midrow_profile[x] = (int) *uptr;
106 if (this->visible)
107 Refresh();
108 }
109
OnPaint(wxPaintEvent & WXUNUSED (evt))110 void ProfileWindow::OnPaint(wxPaintEvent& WXUNUSED(evt))
111 {
112 wxAutoBufferedPaintDC dc(this);
113
114 dc.SetBackground(wxColour(10, 30, 30));
115 dc.Clear();
116
117 if (!pFrame || !pFrame->pGuider || pFrame->pGuider->GetState() == STATE_UNINITIALIZED)
118 return;
119
120 const int xsize = this->GetSize().GetX();
121 const int ysize = this->GetSize().GetY();
122
123 #if defined (__APPLE__)
124 const wxFont& smallFont = *wxSMALL_FONT;
125 #else
126 const wxFont& smallFont = *wxSWISS_FONT;
127 #endif
128 dc.SetFont(smallFont);
129 int smallFontHeight = dc.GetTextExtent("0").GetHeight();
130
131 bool inFocusingMode = (ysize > xsize/2 + 20);
132
133 wxFont largeFont;
134 int largeFontHeight;
135 int labelTextHeight;
136
137 if (inFocusingMode) {
138 //todo: Tuning the scaling factor
139 int scale = ysize / 50;
140 largeFont = smallFont.Scaled(scale);
141
142 dc.SetFont(largeFont);
143 largeFontHeight = dc.GetTextExtent("0").GetHeight();
144 dc.SetFont(smallFont);
145 labelTextHeight = 5 + smallFontHeight + largeFontHeight + 5;
146 }
147 else {
148 labelTextHeight = 5 + smallFontHeight + 5;
149 }
150
151 wxPen RedPen(wxColour(255,0,0));
152 // GreyDashPen = wxPen(wxColour(200,200,200),1, wxDOT);
153 // BluePen = wxPen(wxColour(100,100,255));
154
155 int i;
156 int *profptr;
157 wxString profileLabel;
158 switch (this->mode) { // Figure which profile to use
159 case 0: // mid-row
160 default:
161 profptr = midrow_profile;
162 profileLabel = _("Mid row");
163 break;
164 case 1: // avg row
165 profptr = horiz_profile;
166 profileLabel = _("Avg row");
167 break;
168 case 2:
169 profptr = vert_profile;
170 profileLabel = _("Avg col");
171 break;
172 }
173
174 float fwhm = 0.f;
175
176 // Figure max and min
177 int Prof_Min, Prof_Max, Prof_Mid;
178 Prof_Min = Prof_Max = *profptr;
179
180 for (i = 1; i < FULLW; i++) {
181 if (*(profptr + i) < Prof_Min)
182 Prof_Min = *(profptr + i);
183 else if (*(profptr + i) > Prof_Max)
184 Prof_Max = *(profptr + i);
185 }
186
187 wxPoint Prof[FULLW];
188
189 if (Prof_Min < Prof_Max)
190 {
191 Prof_Mid = (Prof_Max - Prof_Min) / 2 + Prof_Min;
192 // Figure the actual points in the window
193 float Prof_Range = (float)(Prof_Max - Prof_Min) / (float)(ysize - labelTextHeight - 5);
194 if (!Prof_Range) Prof_Range = 1;
195 int wprof = (xsize - 15) / 2 - 5;
196 wprof /= 20;
197 for (i = 0; i < FULLW; i++)
198 Prof[i] = wxPoint(5 + i * wprof, ysize - labelTextHeight - ((float)(*(profptr + i) - Prof_Min) / Prof_Range));
199
200 // fwhm
201 int x1 = 0;
202 int x2 = 0;
203 int profval;
204 int profvalprec;
205 for (i = 1; i < FULLW; i++)
206 {
207 profval = *(profptr + i);
208 profvalprec = *(profptr + i - 1);
209 if (profvalprec <= Prof_Mid && profval >= Prof_Mid)
210 x1 = i;
211 else if (profvalprec >= Prof_Mid && profval <= Prof_Mid)
212 x2 = i;
213 }
214 profval = *(profptr + x1);
215 profvalprec = *(profptr + x1 - 1);
216 float f1 = (float)x1 - (float)(profval - Prof_Mid) / (float)(profval - profvalprec);
217 profval = *(profptr + x2);
218 profvalprec = *(profptr + x2 - 1);
219 float f2 = (float)x2 - (float)(profvalprec - Prof_Mid) / (float)(profvalprec - profval);
220 fwhm = f2 - f1;
221
222 // Draw it
223 dc.SetPen(RedPen);
224 dc.DrawLines(FULLW, Prof);
225 }
226
227 //dc.SetTextForeground(wxColour(100,100,255));
228 dc.SetTextForeground(wxColour(255,0,0));
229
230 const Star& star = pFrame->pGuider->PrimaryStar();
231 if (star.IsValid()) {
232 dc.DrawText(_("Peak"), 3, 3);
233 dc.DrawText(wxString::Format("%u", star.PeakVal), 3, 3 + smallFontHeight);
234 }
235
236 float hfd = star.HFD;
237 if (hfd != 0.f) {
238 float hfdArcSec = hfd * pFrame->GetCameraPixelScale();
239 if (inFocusingMode) {
240 dc.DrawText(wxString::Format(_("%s FWHM: %.2f"), profileLabel, fwhm), 5, ysize - labelTextHeight + 5);
241 int x = 5;
242 wxString s(_("HFD: "));
243 dc.DrawText(s, x, ysize - largeFontHeight / 2 - smallFontHeight / 2);
244 x += dc.GetTextExtent(s).GetWidth();
245
246 dc.SetFont(largeFont);
247 s = wxString::Format(_T("%.2f"), hfd);
248 dc.DrawText(s, x, ysize - largeFontHeight);
249 x += dc.GetTextExtent(s).GetWidth();
250
251 dc.SetFont(smallFont);
252 s = wxString::Format(_T(" %.2f\""), hfdArcSec);
253 dc.DrawText(s, x, ysize - largeFontHeight / 2 - smallFontHeight / 2);
254 }
255 else {
256 dc.DrawText(wxString::Format(_("%s FWHM: %.2f, HFD: %.2f (%.2f\")"), profileLabel, fwhm, hfd, hfdArcSec), 5, ysize - smallFontHeight - 5);
257 }
258 }
259 else {
260 dc.DrawText(wxString::Format(_("%s FWHM: %.2f"), profileLabel, fwhm), 5, ysize - smallFontHeight - 5);
261 }
262
263 // JBW: draw zoomed guidestar subframe (todo: make constants symbolic)
264 wxImage* img = pFrame->pGuider->DisplayedImage();
265 double scaleFactor = pFrame->pGuider->ScaleFactor();
266 if (img) {
267 int xoffset = (xsize - 15) / 2;
268 int width = xsize - xoffset - 5;
269 if (width > ysize + 5) width = ysize - 5;
270 int midwidth = width / 2;
271 // grab width(30) px box around lock pos, scale by 2 & display next to profile
272 double LockX = pFrame->pGuider->LockPosition().X * scaleFactor;
273 double LockY = pFrame->pGuider->LockPosition().Y * scaleFactor;
274 double dStarX = LockX - pFrame->pGuider->CurrentPosition().X * scaleFactor;
275 double dStarY = LockY - pFrame->pGuider->CurrentPosition().Y * scaleFactor;
276 // grab the subframe
277 wxBitmap dBmp(*img);
278 int lkx = ROUND(LockX);
279 int l = std::max(0, lkx - 15);
280 int r = std::min(dBmp.GetWidth() - 1, lkx + 15);
281 int w = std::min(lkx - l, r - lkx);
282 int lky = ROUND(LockY);
283 int t = std::max(0, lky - 15);
284 int b = std::min(dBmp.GetHeight() - 1, lky + 15);
285 int h = std::min(lky - t, b - lky);
286 int sz = std::min(w, h);
287
288 wxBitmap subDBmp = dBmp.GetSubBitmap(wxRect(lkx - sz, lky - sz, sz * 2, sz * 2));
289 wxImage subDImg = subDBmp.ConvertToImage();
290 // scale by 2
291 wxBitmap zoomedDBmp(subDImg.Rescale(width, width, wxIMAGE_QUALITY_HIGH));
292 wxMemoryDC tmpMdc;
293 tmpMdc.SelectObject(zoomedDBmp);
294 // blit into profile DC
295 dc.Blit(xoffset, 0, width, width, &tmpMdc, 0, 0, wxCOPY, false);
296 // lines for the lock pos + red dot at star centroid
297 dc.SetPen(wxPen(wxColor(0, 200, 0), 1, wxPENSTYLE_DOT));
298 dc.DrawLine(xoffset, midwidth, xoffset + width, midwidth);
299 dc.DrawLine(xoffset + midwidth, 0, xoffset + midwidth, width);
300 if (sz > 0)
301 {
302 // and a small cross at the centroid
303 double starX = xoffset + midwidth - dStarX * (width / (sz * 2)) + 1, starY = midwidth - dStarY * (width / (sz * 2)) + 1;
304 if (starX >= xoffset) {
305 dc.SetPen(RedPen);
306 dc.DrawLine(starX - 3, starY, starX + 3, starY);
307 dc.DrawLine(starX, starY - 3, starX, starY + 3);
308 }
309 }
310 }
311 }
312
313