1 /******************************************************************************
2 * $Id: wind_history.cpp, v1.0 2010/08/30 tom-r Exp $
3 *
4 * Project: OpenCPN
5 * Purpose: Dashboard Plugin
6 * Author: Thomas Rauch
7 *
8 ***************************************************************************
9 * Copyright (C) 2010 by David S. Register *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
25 ***************************************************************************
26 */
27
28 #include "wind_history.h"
29 #include "wx28compat.h"
30
31 // For compilers that support precompilation, includes "wx/wx.h".
32 #include <wx/wxprec.h>
33
34 #ifdef __BORLANDC__
35 #pragma hdrstop
36 #endif
37
38 // for all others, include the necessary headers (this file is usually all you
39 // need because it includes almost all "standard" wxWidgets headers)
40 #ifndef WX_PRECOMP
41 #include <wx/wx.h>
42 #endif
43
44
45 //************************************************************************************************************************
46 // History of wind direction
47 //************************************************************************************************************************
48
DashboardInstrument_WindDirHistory(wxWindow * parent,wxWindowID id,wxString title)49 DashboardInstrument_WindDirHistory::DashboardInstrument_WindDirHistory( wxWindow *parent, wxWindowID id, wxString title) :
50 DashboardInstrument(parent, id, title, OCPN_DBP_STC_TWD | OCPN_DBP_STC_TWS)
51 { SetDrawSoloInPane(true);
52 m_MaxWindDir = -1;
53 m_WindDir = -1;
54 m_WindDirRange=90;
55 m_MaxWindSpd = 0;
56 m_WindSpeedUnit = _("--");
57 m_TotalMaxWindSpd = 0;
58 m_WindSpd = 0;
59 m_TopLineHeight=30;
60 m_SpdRecCnt=0;
61 m_DirRecCnt=0;
62 m_SpdStartVal=-1;
63 m_DirStartVal=-1;
64 m_IsRunning=false;
65 m_SampleCount=0;
66 m_LeftLegend=3;
67 m_RightLegend=3;
68 for (int idx = 0; idx < WIND_RECORD_COUNT; idx++) {
69 m_ArrayWindDirHistory[idx] = -1;
70 m_ArrayWindSpdHistory[idx] = -1;
71 m_ExpSmoothArrayWindSpd[idx] = -1;
72 m_ExpSmoothArrayWindDir[idx] = -1;
73 m_ArrayRecTime[idx]=wxDateTime::Now().GetTm( );
74 m_ArrayRecTime[idx].year=999;
75 }
76 alpha=0.01; //smoothing constant
77 m_WindowRect=GetClientRect();
78 m_DrawAreaRect=GetClientRect();
79 m_DrawAreaRect.SetHeight(m_WindowRect.height-m_TopLineHeight-m_TitleHeight);
80 }
81
GetSize(int orient,wxSize hint)82 wxSize DashboardInstrument_WindDirHistory::GetSize( int orient, wxSize hint )
83 {
84 wxClientDC dc(this);
85 int w;
86 dc.GetTextExtent(m_title, &w, &m_TitleHeight, 0, 0, g_pFontTitle);
87 if( orient == wxHORIZONTAL ) {
88 return wxSize( DefaultWidth, wxMax(m_TitleHeight+140, hint.y) );
89 }
90 else {
91 return wxSize( wxMax(hint.x, DefaultWidth), wxMax(m_TitleHeight+140, hint.y) );
92 }
93 }
SetData(int st,double data,wxString unit)94 void DashboardInstrument_WindDirHistory::SetData(int st, double data, wxString unit)
95 {
96 if (st == OCPN_DBP_STC_TWD || st == OCPN_DBP_STC_TWS) {
97 if (st == OCPN_DBP_STC_TWD) {
98 m_WindDir = data;
99 if (m_DirRecCnt <= 5){
100 m_DirStartVal += data;
101 m_DirRecCnt++;
102 }
103 }
104 if (st == OCPN_DBP_STC_TWS && (std::isnan(data) || data < 200.0)) {
105 m_WindSpd = data;
106 // if unit changes, reset everything ...
107 if (unit != m_WindSpeedUnit && m_WindSpeedUnit != _("--")) {
108 m_MaxWindDir = -1;
109 m_WindDir = -1;
110 m_WindDirRange = 90;
111 m_MaxWindSpd = 0;
112 m_TotalMaxWindSpd = 0;
113 m_WindSpd = 0;
114 m_SpdRecCnt = 0;
115 m_DirRecCnt = 0;
116 m_SpdStartVal = -1;
117 m_DirStartVal = -1;
118 m_IsRunning = false;
119 m_SampleCount = 0;
120 m_LeftLegend = 3;
121 m_RightLegend = 3;
122 for (int idx = 0; idx < WIND_RECORD_COUNT; idx++) {
123 m_ArrayWindDirHistory[idx] = -1;
124 m_ArrayWindSpdHistory[idx] = -1;
125 m_ExpSmoothArrayWindSpd[idx] = -1;
126 m_ExpSmoothArrayWindDir[idx] = -1;
127 m_ArrayRecTime[idx] = wxDateTime::Now().GetTm( );
128 m_ArrayRecTime[idx].year = 999;
129 }
130 }
131 m_WindSpeedUnit = unit;
132 if (m_SpdRecCnt <= 5){
133 m_SpdStartVal += data;
134 m_SpdRecCnt++;
135 }
136 }
137 if ( m_SpdRecCnt == 5 && m_DirRecCnt == 5) {
138 m_WindSpd= m_SpdStartVal/5;
139 m_WindDir = m_DirStartVal/5;
140 m_oldDirVal=m_WindDir; // make sure we don't get a diff > or <180 in the initial run
141 }
142 //start working after we collected 5 records each, as start values for the smoothed curves
143 if (m_SpdRecCnt > 5 && m_DirRecCnt > 5) {
144 m_IsRunning=true;
145 m_SampleCount = m_SampleCount<WIND_RECORD_COUNT? m_SampleCount+1:WIND_RECORD_COUNT;
146 m_MaxWindDir = 0;
147 m_MinWindDir = 360;
148 m_MaxWindSpd = 0;
149 //data shifting
150 for (int idx = 1; idx < WIND_RECORD_COUNT; idx++) {
151 if (WIND_RECORD_COUNT-m_SampleCount <= idx)
152 m_MinWindDir = wxMin(m_ArrayWindDirHistory[idx],m_MinWindDir);
153 m_MaxWindDir = wxMax(m_ArrayWindDirHistory[idx-1],m_MaxWindDir);
154 m_MaxWindSpd = wxMax(m_ArrayWindSpdHistory[idx-1],m_MaxWindSpd);
155 m_ArrayWindDirHistory[idx-1] = m_ArrayWindDirHistory[idx];
156 m_ArrayWindSpdHistory[idx-1] = m_ArrayWindSpdHistory[idx];
157 m_ExpSmoothArrayWindSpd[idx-1]=m_ExpSmoothArrayWindSpd[idx];
158 m_ExpSmoothArrayWindDir[idx-1]=m_ExpSmoothArrayWindDir[idx];
159 m_ArrayRecTime[idx-1]=m_ArrayRecTime[idx];
160 }
161 double diff=m_WindDir - m_oldDirVal;
162 if (diff < -270) {
163 m_WindDir+=360;
164 }
165 else
166 if( diff > 270) {
167 m_WindDir-=360;
168 }
169 m_ArrayWindDirHistory[WIND_RECORD_COUNT-1] = m_WindDir;
170 m_ArrayWindSpdHistory[WIND_RECORD_COUNT-1] = m_WindSpd;
171 if( m_SampleCount<2) {
172 m_ArrayWindSpdHistory[WIND_RECORD_COUNT-2] = m_WindSpd;
173 m_ExpSmoothArrayWindSpd[WIND_RECORD_COUNT-2]= m_WindSpd;
174 m_ArrayWindDirHistory[WIND_RECORD_COUNT-2] = m_WindDir;
175 m_ExpSmoothArrayWindDir[WIND_RECORD_COUNT-2]= m_WindDir;
176 }
177 m_ExpSmoothArrayWindSpd[WIND_RECORD_COUNT-1]=alpha*m_ArrayWindSpdHistory[WIND_RECORD_COUNT-2]+(1-alpha)*m_ExpSmoothArrayWindSpd[WIND_RECORD_COUNT-2];
178 m_ExpSmoothArrayWindDir[WIND_RECORD_COUNT-1]=alpha*m_ArrayWindDirHistory[WIND_RECORD_COUNT-2]+(1-alpha)*m_ExpSmoothArrayWindDir[WIND_RECORD_COUNT-2];
179 m_ArrayRecTime[WIND_RECORD_COUNT-1]=wxDateTime::Now().GetTm( );
180 m_oldDirVal=m_ExpSmoothArrayWindDir[WIND_RECORD_COUNT-1];
181 //include the new/latest value in the max/min value test too
182 m_MaxWindDir = wxMax(m_WindDir,m_MaxWindDir);
183 m_MinWindDir = wxMin(m_WindDir,m_MinWindDir);
184 m_MaxWindSpd = wxMax(m_WindSpd,m_MaxWindSpd);
185 //get the overall max Wind Speed
186 m_TotalMaxWindSpd = wxMax(m_WindSpd,m_TotalMaxWindSpd);
187
188 // set wind angle scale to full +/- 90° depending on the real max/min value recorded
189 SetMinMaxWindScale();
190 }
191 }
192 }
193
Draw(wxGCDC * dc)194 void DashboardInstrument_WindDirHistory::Draw(wxGCDC* dc)
195 {
196 m_WindowRect = GetClientRect();
197 m_DrawAreaRect=GetClientRect();
198 m_DrawAreaRect.SetHeight(m_WindowRect.height-m_TopLineHeight-m_TitleHeight);
199 m_DrawAreaRect.SetX (m_LeftLegend+3);
200 DrawBackground(dc);
201 DrawForeground(dc);
202 }
203
204 //*********************************************************************************
205 // determine and set min and max values for the direction
206 //*********************************************************************************
SetMinMaxWindScale()207 void DashboardInstrument_WindDirHistory::SetMinMaxWindScale()
208 {
209 // set wind direction legend to full +/- 90° depending on the real max/min value recorded
210 // example : max wind dir. = 45° ==> max = 90°
211 // min wind dir. = 45° ==> min = 0°
212 //first calculate the max wind direction
213 int fulldeg = m_MaxWindDir / 90; //we explicitly chop off the decimals by type conversion from double to int !
214 if(fulldeg == 0)
215 fulldeg=m_MaxWindDir<0 ?0:1;
216 else if (m_MaxWindDir>0)
217 fulldeg+=1;
218 m_MaxWindDir=fulldeg*90;
219 //now calculate the min wind direction
220 fulldeg = m_MinWindDir / 90;
221 if(fulldeg == 0)
222 fulldeg=m_MinWindDir<0 ?-1:0;
223 else
224 fulldeg=m_MinWindDir>0 ? fulldeg:(fulldeg-1);
225 m_MinWindDir=fulldeg*90;
226
227 // limit the visible wind dir range to 360°; remove the extra range on the opposite side of the current wind dir value
228 m_WindDirRange=m_MaxWindDir-m_MinWindDir;
229 if (m_WindDirRange > 360) {
230 int diff2min=m_WindDir-m_MinWindDir; //diff between min value and current value
231 int diff2max=m_MaxWindDir-m_WindDir; //diff between max value and current value
232 if(diff2min > diff2max) {
233 while (m_WindDirRange > 360) {
234 m_MinWindDir+=90;
235 m_WindDirRange=m_MaxWindDir-m_MinWindDir;
236 }
237 }
238 if(diff2min < diff2max) {
239 while (m_WindDirRange > 360) {
240 m_MaxWindDir-=90;
241 m_WindDirRange=m_MaxWindDir-m_MinWindDir;
242 }
243 }
244 }
245 }
246 //*********************************************************************************
247 // wind direction legend
248 //*********************************************************************************
DrawWindDirScale(wxGCDC * dc)249 void DashboardInstrument_WindDirHistory::DrawWindDirScale(wxGCDC* dc)
250 {
251 wxString label1,label2,label3,label4,label5;
252 wxColour cl;
253 wxPen pen;
254 int width, height;
255 cl=wxColour(204,41,41,255); //red, opague
256
257 dc->SetTextForeground(cl);
258 dc->SetFont(*g_pFontSmall);
259 if(!m_IsRunning) {
260 label1=_T("---");
261 label2=_T("---");
262 label3=_T("---");
263 label4=_T("---");
264 label5=_T("---");
265 }
266 else {
267 // label 1 : legend for bottom line. By definition always w/o decimals
268 double tempdir=m_MinWindDir;
269 while (tempdir < 0) tempdir+=360;
270 while (tempdir >= 360) tempdir-=360;
271 label1=GetWindDirStr(wxString::Format(_T("%.1f"), tempdir));
272 // label 2 : 1/4
273 tempdir=m_MinWindDir+m_WindDirRange/4.;
274 while (tempdir < 0) tempdir+=360;
275 while (tempdir >= 360) tempdir-=360;
276 label2=GetWindDirStr(wxString::Format(_T("%.1f"), tempdir));
277 // label 3 : legend for center line
278 tempdir=m_MinWindDir+m_WindDirRange/2;
279 while (tempdir < 0) tempdir+=360;
280 while (tempdir >= 360) tempdir-=360;
281 label3=GetWindDirStr(wxString::Format(_T("%.1f"), tempdir));
282 // label 4 : 3/4
283 tempdir=m_MinWindDir+m_WindDirRange*0.75;
284 while (tempdir < 0) tempdir+=360;
285 while (tempdir >= 360) tempdir-=360;
286 label4=GetWindDirStr(wxString::Format(_T("%.1f"), tempdir));
287 // label 5 : legend for top line
288 tempdir=m_MaxWindDir;
289 while (tempdir < 0) tempdir+=360;
290 while (tempdir >= 360) tempdir-=360;
291 label5=GetWindDirStr(wxString::Format(_T("%.1f"), tempdir));
292 }
293 //draw the legend with the labels; find the widest string and store it in m_RightLegend.
294 // m_RightLegend is the basis for the horizontal lines !
295 dc->GetTextExtent(label5, &width, &height, 0, 0, g_pFontSmall);
296 m_RightLegend=width;
297 dc->GetTextExtent(label4, &width, &height, 0, 0, g_pFontSmall);
298 m_RightLegend=wxMax(width,m_RightLegend);
299 dc->GetTextExtent(label3, &width, &height, 0, 0, g_pFontSmall);
300 m_RightLegend=wxMax(width,m_RightLegend);
301 dc->GetTextExtent(label2, &width, &height, 0, 0, g_pFontSmall);
302 m_RightLegend=wxMax(width,m_RightLegend);
303 dc->GetTextExtent(label1, &width, &height, 0, 0, g_pFontSmall);
304 m_RightLegend=wxMax(width,m_RightLegend);
305
306 m_RightLegend+=4; //leave some space to the edge
307 dc->DrawText(label5, m_WindowRect.width-m_RightLegend, m_TopLineHeight-height/2);
308 dc->DrawText(label4, m_WindowRect.width-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height/4-height/2));
309 dc->DrawText(label3, m_WindowRect.width-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height/2-height/2));
310 dc->DrawText(label2, m_WindowRect.width-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.75-height/2));
311 dc->DrawText(label1, m_WindowRect.width-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height-height/2));
312 }
313
314 //*********************************************************************************
315 // draw wind speed scale
316 //*********************************************************************************
DrawWindSpeedScale(wxGCDC * dc)317 void DashboardInstrument_WindDirHistory::DrawWindSpeedScale(wxGCDC* dc)
318 {
319 wxString label1,label2,label3,label4,label5;
320 wxColour cl;
321 int width, height;
322 double val1;
323 double WindSpdScale;
324
325 cl=wxColour(61,61,204,255);
326 dc->SetTextForeground(cl);
327 dc->SetFont(*g_pFontSmall);
328 //round maxWindSpd up to the next full knot; nicer view ...
329 m_MaxWindSpdScale=(int)m_MaxWindSpd + 1;
330 if(!m_IsRunning) {
331 label1.Printf(_("--- %s"), m_WindSpeedUnit.c_str());
332 label2 = label1;
333 label3 = label1;
334 label4 = label1;
335 label5 = label1;
336 }
337 else {
338 /*we round the speed up to the next full knot ==> the top and bottom line have full numbers as legend (e.g. 23 kn -- 0 kn)
339 but the intermediate lines may have decimal values (e.g. center line : 23/2=11.5 or quarter line 23/4=5.75), so in worst case
340 we end up with 23 - 17.25 - 11.5 - 5.75 - 0
341 The goal is to draw the legend with decimals only, if we really have them !
342 */
343 // top legend for max wind
344 label1.Printf(_T("%.0f %s"), m_MaxWindSpdScale,m_WindSpeedUnit.c_str());
345 // 3/4 legend
346 WindSpdScale=m_MaxWindSpdScale*3./4.;
347 // do we need a decimal ?
348 val1=(int)((WindSpdScale-(int)WindSpdScale)*100);
349 if(val1==25 || val1==75) // it's a .25 or a .75
350 label2.Printf(_T("%.2f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
351 else if (val1 == 50)
352 label2.Printf(_T("%.1f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
353 else
354 label2.Printf(_T("%.0f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
355 // center legend
356 WindSpdScale=m_MaxWindSpdScale/2.;
357 // center line can either have a .0 or .5 value !
358 if((int)(WindSpdScale*10) % 10 == 5)
359 label3.Printf(_T("%.1f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
360 else
361 label3.Printf(_T("%.0f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
362
363 // 1/4 legend
364 WindSpdScale=m_MaxWindSpdScale/4.;
365 // do we need a decimal ?
366 val1=(int)((WindSpdScale-(int)WindSpdScale)*100);
367 if(val1==25 || val1==75)
368 label4.Printf(_T("%.2f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
369 else if (val1 == 50)
370 label4.Printf(_T("%.1f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
371 else
372 label4.Printf(_T("%.0f %s"), WindSpdScale, m_WindSpeedUnit.c_str());
373
374 //bottom legend for min wind, always 0
375 label5.Printf(_T("%.0f %s"), 0.0, m_WindSpeedUnit.c_str());
376 }
377 dc->GetTextExtent(label1, &m_LeftLegend, &height, 0, 0, g_pFontSmall);
378 dc->DrawText(label1, 4, (int)(m_TopLineHeight-height/2));
379 dc->GetTextExtent(label2, &width, &height, 0, 0, g_pFontSmall);
380 dc->DrawText(label2, 4, (int)(m_TopLineHeight+m_DrawAreaRect.height/4-height/2));
381 m_LeftLegend = wxMax(width,m_LeftLegend);
382 dc->GetTextExtent(label3, &width, &height, 0, 0, g_pFontSmall);
383 dc->DrawText(label3, 4, (int)(m_TopLineHeight+m_DrawAreaRect.height/2-height/2));
384 m_LeftLegend = wxMax(width,m_LeftLegend);
385 dc->GetTextExtent(label4, &width, &height, 0, 0, g_pFontSmall);
386 dc->DrawText(label4, 4, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.75-height/2));
387 m_LeftLegend = wxMax(width,m_LeftLegend);
388 dc->GetTextExtent(label5, &width, &height, 0, 0, g_pFontSmall);
389 dc->DrawText(label5, 4, (int)(m_TopLineHeight+m_DrawAreaRect.height-height/2));
390 m_LeftLegend = wxMax(width,m_LeftLegend);
391 m_LeftLegend+=4;
392 }
393
394 //*********************************************************************************
395 //draw background
396 //*********************************************************************************
DrawBackground(wxGCDC * dc)397 void DashboardInstrument_WindDirHistory::DrawBackground(wxGCDC* dc)
398 {
399 wxString label,label1,label2,label3,label4,label5;
400 wxColour cl;
401 wxPen pen;
402 //---------------------------------------------------------------------------------
403 // draw legends for speed and direction
404 //---------------------------------------------------------------------------------
405 DrawWindDirScale(dc);
406 DrawWindSpeedScale(dc);
407
408 //---------------------------------------------------------------------------------
409 // horizontal lines
410 //---------------------------------------------------------------------------------
411 GetGlobalColor(_T("UBLCK"), &cl);
412 pen.SetColour(cl);
413 dc->SetPen(pen);
414 dc->DrawLine(m_LeftLegend+3, m_TopLineHeight, m_WindowRect.width-3-m_RightLegend, m_TopLineHeight); // the upper line
415 dc->DrawLine(m_LeftLegend+3, (int)(m_TopLineHeight+m_DrawAreaRect.height), m_WindowRect.width-3-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height));
416 pen.SetStyle(wxPENSTYLE_DOT);
417 dc->SetPen(pen);
418 dc->DrawLine(m_LeftLegend+3, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.25), m_WindowRect.width-3-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.25));
419 dc->DrawLine(m_LeftLegend+3, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.75), m_WindowRect.width-3-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.75));
420 #ifdef __WXMSW__
421 pen.SetStyle(wxPENSTYLE_SHORT_DASH);
422 dc->SetPen(pen);
423 #endif
424 dc->DrawLine(m_LeftLegend+3, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.5), m_WindowRect.width-3-m_RightLegend, (int)(m_TopLineHeight+m_DrawAreaRect.height*0.5));
425 }
426
427 //***********************************************************************************
428 // convert numerical wind direction values to text, used in the wind direction legend
429 //***********************************************************************************
GetWindDirStr(wxString WindDir)430 wxString DashboardInstrument_WindDirHistory::GetWindDirStr(wxString WindDir)
431 {
432 if ( WindDir == _T("0.0") || WindDir == _T("360.0") )
433 return _("N");
434 else
435 if (WindDir == _T("22.5"))
436 return _("NNE");
437 else
438 if (WindDir == _T("45.0"))
439 return _("NE");
440 else
441 if (WindDir == _T("67.5"))
442 return _("ENE");
443 else
444 if (WindDir == _T("90.0"))
445 return _("E");
446 else
447 if (WindDir == _T("112.5"))
448 return _("ESE");
449 else
450 if (WindDir == _T("135.0"))
451 return _("SE");
452 else
453 if (WindDir == _T("157.5"))
454 return _("SSE");
455 else
456 if (WindDir == _T("180.0"))
457 return _("S");
458 else
459 if (WindDir == _T("202.5"))
460 return _("SSW");
461 else
462 if (WindDir == _T("225.0"))
463 return _("SW");
464 else
465 if (WindDir == _T("247.5"))
466 return _("WSW");
467 else
468 if (WindDir == _T("270.0"))
469 return _("W");
470 else
471 if (WindDir == _T("292.5"))
472 return _("WNW");
473 else
474 if (WindDir == _T("315.0"))
475 return _("NW");
476 else
477 if (WindDir == _T("337.5"))
478 return _("NNW");
479 else
480 return WindDir;
481 }
482
483 //*********************************************************************************
484 //draw foreground
485 //*********************************************************************************
DrawForeground(wxGCDC * dc)486 void DashboardInstrument_WindDirHistory::DrawForeground(wxGCDC* dc)
487 {
488 wxColour col;
489 double ratioH;
490 int degw,degh;
491 int width,height,sec,min,hour;
492 double dir;
493 wxString WindAngle,WindSpeed;
494 wxPen pen;
495 wxString label;
496
497 //---------------------------------------------------------------------------------
498 // wind direction
499 //---------------------------------------------------------------------------------
500 dc->SetFont(*g_pFontData);
501 col=wxColour(204,41,41,255); //red, opaque
502 dc->SetTextForeground(col);
503 if(!m_IsRunning)
504 WindAngle=_T("TWD ---");
505 else {
506 dir=m_WindDir;
507 while(dir > 360) dir-=360;
508 while(dir <0 ) dir+=360;
509 if ( !std::isnan(dir) )
510 WindAngle=wxString::Format(_T("TWD %3.0f"), dir)+DEGREE_SIGN;
511 else
512 WindAngle = wxString::Format(_T("TWD ---")) + DEGREE_SIGN;
513 }
514 dc->GetTextExtent(WindAngle, °w, °h, 0, 0, g_pFontData);
515 dc->DrawText(WindAngle, m_WindowRect.width-degw-m_RightLegend-3, m_TopLineHeight-degh);
516 pen.SetStyle(wxPENSTYLE_SOLID);
517 pen.SetColour(wxColour(204,41,41 ,96)); //red, transparent
518 pen.SetWidth(1);
519 dc->SetPen( pen );
520 ratioH = (double) m_DrawAreaRect.height / m_WindDirRange;
521 m_DrawAreaRect.SetWidth(m_WindowRect.width - 6 - m_LeftLegend-m_RightLegend);
522 m_ratioW = double(m_DrawAreaRect.width) / (WIND_RECORD_COUNT-1);
523
524 //---------------------------------------------------------------------------------
525 // live direction data
526 //---------------------------------------------------------------------------------
527 wxPoint points[WIND_RECORD_COUNT+2], pointAngle_old;
528 pointAngle_old.x=3+m_LeftLegend;
529 pointAngle_old.y = m_TopLineHeight+m_DrawAreaRect.height - (m_ArrayWindDirHistory[0]-m_MinWindDir) * ratioH;
530 for (int idx = 1; idx < WIND_RECORD_COUNT; idx++) {
531 points[idx].x = idx * m_ratioW + 3 + m_LeftLegend;
532 points[idx].y = m_TopLineHeight+m_DrawAreaRect.height - (m_ArrayWindDirHistory[idx]-m_MinWindDir) * ratioH;
533 if(WIND_RECORD_COUNT-m_SampleCount <= idx && points[idx].y > m_TopLineHeight && pointAngle_old.y> m_TopLineHeight && points[idx].y <=m_TopLineHeight+m_DrawAreaRect.height && pointAngle_old.y<=m_TopLineHeight+m_DrawAreaRect.height)
534 dc->DrawLine( pointAngle_old.x, pointAngle_old.y, points[idx].x,points[idx].y );
535 pointAngle_old.x=points[idx].x;
536 pointAngle_old.y=points[idx].y;
537 }
538
539 //---------------------------------------------------------------------------------
540 //exponential smoothing of direction
541 //---------------------------------------------------------------------------------
542 pen.SetStyle(wxPENSTYLE_SOLID);
543 pen.SetColour(wxColour(204,41,41 ,255));
544 pen.SetWidth(2);
545 dc->SetPen( pen );
546 pointAngle_old.x=3+m_LeftLegend;
547 pointAngle_old.y = m_TopLineHeight+m_DrawAreaRect.height - (m_ExpSmoothArrayWindDir[0]-m_MinWindDir) * ratioH;
548 for (int idx = 1; idx < WIND_RECORD_COUNT; idx++) {
549 points[idx].x = idx * m_ratioW + 3 + m_LeftLegend;
550 points[idx].y = m_TopLineHeight+m_DrawAreaRect.height - (m_ExpSmoothArrayWindDir[idx]-m_MinWindDir) * ratioH;
551 if(WIND_RECORD_COUNT-m_SampleCount <= idx && points[idx].y > m_TopLineHeight && pointAngle_old.y > m_TopLineHeight && points[idx].y <=m_TopLineHeight+m_DrawAreaRect.height && pointAngle_old.y<=m_TopLineHeight+m_DrawAreaRect.height)
552 dc->DrawLine( pointAngle_old.x, pointAngle_old.y, points[idx].x,points[idx].y );
553 pointAngle_old.x=points[idx].x;
554 pointAngle_old.y=points[idx].y;
555 }
556
557 //---------------------------------------------------------------------------------
558 // wind speed
559 //---------------------------------------------------------------------------------
560 col=wxColour(61,61,204,255); //blue, opaque
561 dc->SetFont(*g_pFontData);
562 dc->SetTextForeground(col);
563 if ( !std::isnan(m_WindSpd))
564 WindSpeed=wxString::Format(_T("TWS %3.1f %s "), m_WindSpd, m_WindSpeedUnit.c_str());
565 else
566 WindSpeed = wxString::Format(_T("TWS --- %s "), m_WindSpeedUnit.c_str());
567
568 dc->GetTextExtent(WindSpeed, °w, °h, 0, 0, g_pFontData);
569 dc->DrawText(WindSpeed, m_LeftLegend+3, m_TopLineHeight-degh);
570 dc->SetFont(*g_pFontLabel);
571 //determine the time range of the available data (=oldest data value)
572 int i=0;
573 while(m_ArrayRecTime[i].year == 999 && i<WIND_RECORD_COUNT-1) i++;
574 if (i == WIND_RECORD_COUNT -1) {
575 min=0;
576 hour=0;
577 }
578 else {
579 wxDateTime localTime( m_ArrayRecTime[i] );
580 min=localTime.GetMinute( );
581 hour=localTime.GetHour( );
582 }
583 dc->DrawText(wxString::Format(_("Max %.1f %s since %02d:%02d Overall %.1f %s"), m_MaxWindSpd, m_WindSpeedUnit.c_str(), hour, min, m_TotalMaxWindSpd, m_WindSpeedUnit.c_str()), m_LeftLegend + 3 + 2 + degw, m_TopLineHeight - degh + 5);
584 pen.SetStyle(wxPENSTYLE_SOLID);
585 pen.SetColour(wxColour(61,61,204,96)); //blue, transparent
586 pen.SetWidth(1);
587 dc->SetPen( pen );
588 ratioH = (double)m_DrawAreaRect.height / m_MaxWindSpdScale;
589 wxPoint pointsSpd[WIND_RECORD_COUNT+2],pointSpeed_old;
590 pointSpeed_old.x=m_LeftLegend+3;
591 pointSpeed_old.y = m_TopLineHeight+m_DrawAreaRect.height - m_ArrayWindSpdHistory[0] * ratioH;
592
593 //---------------------------------------------------------------------------------
594 // live speed data
595 //---------------------------------------------------------------------------------
596 for (int idx = 1; idx < WIND_RECORD_COUNT; idx++) {
597 pointsSpd[idx].x = idx * m_ratioW + 3 + m_LeftLegend;
598 pointsSpd[idx].y = m_TopLineHeight+m_DrawAreaRect.height - m_ArrayWindSpdHistory[idx] * ratioH;
599 if(WIND_RECORD_COUNT-m_SampleCount <= idx && pointsSpd[idx].y > m_TopLineHeight && pointSpeed_old.y > m_TopLineHeight && pointsSpd[idx].y <=m_TopLineHeight+m_DrawAreaRect.height && pointSpeed_old.y<=m_TopLineHeight+m_DrawAreaRect.height)
600 dc->DrawLine( pointSpeed_old.x, pointSpeed_old.y, pointsSpd[idx].x,pointsSpd[idx].y );
601 pointSpeed_old.x=pointsSpd[idx].x;
602 pointSpeed_old.y=pointsSpd[idx].y;
603 }
604
605 //---------------------------------------------------------------------------------
606 //exponential smoothing of speed
607 //---------------------------------------------------------------------------------
608 pen.SetStyle(wxPENSTYLE_SOLID);
609 pen.SetColour(wxColour(61,61,204,255)); //blue, opaque
610 pen.SetWidth(2);
611 dc->SetPen( pen );
612 pointSpeed_old.x=m_LeftLegend+3;
613 pointSpeed_old.y = m_TopLineHeight+m_DrawAreaRect.height - m_ExpSmoothArrayWindSpd[0] * ratioH;
614 for (int idx = 1; idx < WIND_RECORD_COUNT; idx++) {
615 pointsSpd[idx].x = idx * m_ratioW + 3 + m_LeftLegend;
616 pointsSpd[idx].y = m_TopLineHeight+m_DrawAreaRect.height - m_ExpSmoothArrayWindSpd[idx] * ratioH;
617 if(WIND_RECORD_COUNT-m_SampleCount <= idx && pointsSpd[idx].y > m_TopLineHeight && pointSpeed_old.y > m_TopLineHeight && pointsSpd[idx].y <=m_TopLineHeight+m_DrawAreaRect.height && pointSpeed_old.y<=m_TopLineHeight+m_DrawAreaRect.height)
618 dc->DrawLine( pointSpeed_old.x, pointSpeed_old.y, pointsSpd[idx].x,pointsSpd[idx].y );
619 pointSpeed_old.x=pointsSpd[idx].x;
620 pointSpeed_old.y=pointsSpd[idx].y;
621 }
622
623 //---------------------------------------------------------------------------------
624 //draw vertical timelines every 5 minutes
625 //---------------------------------------------------------------------------------
626 GetGlobalColor(_T("UBLCK"), &col);
627 pen.SetColour(col);
628 pen.SetStyle(wxPENSTYLE_DOT);
629 dc->SetPen(pen);
630 dc->SetTextForeground(col);
631 dc->SetFont(*g_pFontSmall);
632 int done=-1;
633 wxPoint pointTime;
634 for (int idx = 0; idx < WIND_RECORD_COUNT; idx++) {
635 if(m_ArrayRecTime[idx].year!= 999) {
636 wxDateTime localTime( m_ArrayRecTime[i] );
637 hour = localTime.GetHour( );
638 sec = localTime.GetSecond();
639 min = localTime.GetMinute( );
640 if ( (hour*100+min) != done && (min % 5 == 0 ) && (sec == 0 || sec == 1) ) {
641 pointTime.x = idx * m_ratioW + 3 + m_LeftLegend;
642 dc->DrawLine( pointTime.x, m_TopLineHeight+1, pointTime.x,(m_TopLineHeight+m_DrawAreaRect.height+1) );
643 label.Printf(_T("%02d:%02d"), hour,min);
644 dc->GetTextExtent(label, &width, &height, 0, 0, g_pFontSmall);
645 dc->DrawText(label, pointTime.x-width/2, m_WindowRect.height-height);
646 done=hour*100+min;
647 }
648 }
649 }
650 }
651