1 /******************************************************************************
2  * $Id: dial.cpp, v1.0 2010/08/05 SethDart Exp $
3  *
4  * Project:  OpenCPN
5  * Purpose:  Dashboard Plugin
6  * Author:   Jean-Eudes Onfray
7  *           (Inspired by original work from Andreas Heiming)
8  *
9  ***************************************************************************
10  *   Copyright (C) 2010 by David S. Register   *
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License as published by  *
14  *   the Free Software Foundation; either version 2 of the License, or     *
15  *   (at your option) any later version.                                   *
16  *                                                                         *
17  *   This program is distributed in the hope that it will be useful,       *
18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
20  *   GNU General Public License for more details.                          *
21  *                                                                         *
22  *   You should have received a copy of the GNU General Public License     *
23  *   along with this program; if not, write to the                         *
24  *   Free Software Foundation, Inc.,                                       *
25  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.             *
26  ***************************************************************************
27  */
28 
29 
30 #include "dial.h"
31 #include "wx28compat.h"
32 
33 // For compilers that support precompilation, includes "wx/wx.h".
34 #include <wx/wxprec.h>
35 
36 #ifdef __BORLANDC__
37     #pragma hdrstop
38 #endif
39 
40 // for all others, include the necessary headers (this file is usually all you
41 // need because it includes almost all "standard" wxWidgets headers)
42 #ifndef WX_PRECOMP
43     #include <wx/wx.h>
44 #endif
45 
46 #include <cmath>
47 #include "wx/tokenzr.h"
48 
49 #ifdef __OCPN__ANDROID__
50 #include "qdebug.h"
51 #endif
52 
rad2deg(double angle)53 double rad2deg(double angle)
54 {
55       return angle*180.0/M_PI;
56 }
deg2rad(double angle)57 double deg2rad(double angle)
58 {
59       return angle/180.0*M_PI;
60 }
61 
DashboardInstrument_Dial(wxWindow * parent,wxWindowID id,wxString title,int cap_flag,int s_angle,int r_angle,int s_value,int e_value)62 DashboardInstrument_Dial::DashboardInstrument_Dial( wxWindow *parent, wxWindowID id, wxString title, int cap_flag,
63                   int s_angle, int r_angle, int s_value, int e_value) : DashboardInstrument(parent, id, title, cap_flag)
64 {
65       m_AngleStart = s_angle;
66       m_AngleRange = r_angle;
67       m_MainValueMin = s_value;
68       m_MainValueMax = e_value;
69       m_MainValueCap = cap_flag;
70 
71       m_MainValue = s_value;
72       m_ExtraValue = 0;
73       m_MainValueFormat = _T("%d");
74       m_MainValueUnit = _T("");
75       m_MainValueOption = DIAL_POSITION_NONE;
76       m_ExtraValueFormat = _T("%d");
77       m_ExtraValueUnit = _T("");
78       m_ExtraValueOption = DIAL_POSITION_NONE;
79       m_MarkerOption = DIAL_MARKER_SIMPLE;
80       m_MarkerStep = 1;
81       m_LabelStep = 1;
82       m_MarkerOffset = 1;
83       m_LabelOption = DIAL_LABEL_HORIZONTAL;
84 }
85 
GetSize(int orient,wxSize hint)86 wxSize DashboardInstrument_Dial::GetSize( int orient, wxSize hint )
87 {
88       wxClientDC dc(this);
89       int w;
90       dc.GetTextExtent(m_title, &w, &m_TitleHeight, 0, 0, g_pFontTitle);
91       if( orient == wxHORIZONTAL ) {
92           w = wxMax(hint.y, DefaultWidth+m_TitleHeight);
93           return wxSize( w-m_TitleHeight, w );
94       } else {
95           w = wxMax(hint.x, DefaultWidth);
96           return wxSize( w, m_TitleHeight+w );
97       }
98 }
99 
SetData(int st,double data,wxString unit)100 void DashboardInstrument_Dial::SetData(int st, double data, wxString unit)
101 {
102       if (st == m_MainValueCap)
103       {
104             m_MainValue = data;
105             m_MainValueUnit = unit;
106       }
107       else if (st == m_ExtraValueCap)
108       {
109             m_ExtraValue = data;
110             m_ExtraValueUnit = unit;
111       }
112       Refresh();
113 }
114 
Draw(wxGCDC * bdc)115 void DashboardInstrument_Dial::Draw(wxGCDC* bdc)
116 {
117     wxColour c1;
118     GetGlobalColor(_T("DASHB"), &c1);
119     wxBrush b1(c1);
120     bdc->SetBackground(b1);
121     bdc->Clear();
122 
123     wxSize size = GetClientSize();
124     m_cx = size.x / 2;
125     int availableHeight = size.y - m_TitleHeight - 6;
126     int width, height;
127     bdc->GetTextExtent( _T("000"), &width, &height, 0, 0, g_pFontLabel );
128     m_cy = m_TitleHeight + 2;
129     m_cy += availableHeight / 2;
130     m_radius = availableHeight / 2;
131 
132 
133     DrawFrame(bdc);
134     DrawLabels(bdc);
135     DrawMarkers(bdc);
136     DrawBackground(bdc);
137     DrawData(bdc, m_MainValue, m_MainValueUnit, m_MainValueFormat, m_MainValueOption);
138     DrawData(bdc, m_ExtraValue, m_ExtraValueUnit, m_ExtraValueFormat, m_ExtraValueOption);
139     DrawForeground(bdc);
140 }
141 
DrawFrame(wxGCDC * dc)142 void DashboardInstrument_Dial::DrawFrame( wxGCDC* dc )
143 {
144     wxSize size = GetClientSize();
145     wxColour cl;
146     GetGlobalColor( _T("DASHL"), &cl );
147     dc->SetTextForeground( cl );
148     dc->SetBrush( *wxTRANSPARENT_BRUSH);
149 
150     int penwidth = 1 + size.x / 100;
151     wxPen pen( cl, penwidth, wxPENSTYLE_SOLID );
152 
153     if( m_MarkerOption == DIAL_MARKER_REDGREENBAR ) {
154         pen.SetWidth( penwidth * 2 );
155         GetGlobalColor( _T("DASHR"), &cl );
156         pen.SetColour( cl );
157         dc->SetPen( pen );
158         double angle1 = deg2rad( 270 ); // 305-ANGLE_OFFSET
159         double angle2 = deg2rad( 90 ); // 55-ANGLE_OFFSET
160         int radi = m_radius - 1 - penwidth;
161         wxCoord x1 = m_cx + ( ( radi ) * cos( angle1 ) );
162         wxCoord y1 = m_cy + ( ( radi ) * sin( angle1 ) );
163         wxCoord x2 = m_cx + ( ( radi ) * cos( angle2 ) );
164         wxCoord y2 = m_cy + ( ( radi ) * sin( angle2 ) );
165         dc->DrawArc( x1, y1, x2, y2, m_cx, m_cy );
166 
167         GetGlobalColor( _T("DASHG"), &cl );
168         pen.SetColour( cl );
169         dc->SetPen( pen );
170         angle1 = deg2rad( 89 ); // 305-ANGLE_OFFSET
171         angle2 = deg2rad( 271 ); // 55-ANGLE_OFFSET
172         x1 = m_cx + ( ( radi ) * cos( angle1 ) );
173         y1 = m_cy + ( ( radi ) * sin( angle1 ) );
174         x2 = m_cx + ( ( radi ) * cos( angle2 ) );
175         y2 = m_cy + ( ( radi ) * sin( angle2 ) );
176         dc->DrawArc( x1, y1, x2, y2, m_cx, m_cy );
177 
178         // Some platforms have trouble with transparent pen.
179         // so we simply draw arcs for the outer ring.
180         GetGlobalColor( _T("DASHF"), &cl );
181         pen.SetWidth( penwidth );
182         pen.SetColour( cl );
183         dc->SetPen( pen );
184         angle1 = deg2rad( 0 );
185         angle2 = deg2rad( 180 );
186         radi = m_radius - 1;
187 
188         x1 = m_cx + ( ( radi ) * cos( angle1 ) );
189         y1 = m_cy + ( ( radi ) * sin( angle1 ) );
190         x2 = m_cx + ( ( radi ) * cos( angle2 ) );
191         y2 = m_cy + ( ( radi ) * sin( angle2 ) );
192         dc->DrawArc( x1, y1, x2, y2, m_cx, m_cy );
193         dc->DrawArc( x2, y2, x1, y1, m_cx, m_cy );
194 
195     }
196     else{
197         GetGlobalColor( _T("DASHF"), &cl );
198         pen.SetColour( cl );
199         dc->SetPen( pen );
200         dc->DrawCircle( m_cx, m_cy, m_radius );
201     }
202 }
203 
DrawMarkers(wxGCDC * dc)204 void DashboardInstrument_Dial::DrawMarkers(wxGCDC* dc)
205 {
206     if( m_MarkerOption == DIAL_MARKER_NONE ) return;
207 
208     wxColour cl;
209     GetGlobalColor( _T("DASHF"), &cl );
210     int penwidth = GetClientSize().x / 100;
211     wxPen pen( cl, penwidth, wxPENSTYLE_SOLID );
212     dc->SetPen( pen );
213 
214     int diff_angle = m_AngleStart + m_AngleRange - ANGLE_OFFSET;
215     // angle between markers
216     double abm = m_AngleRange * m_MarkerStep / ( m_MainValueMax - m_MainValueMin );
217     // don't draw last value, it's already done as first
218     if( m_AngleRange == 360 ) diff_angle -= abm;
219 
220     int offset = 0;
221     for( double angle = m_AngleStart - ANGLE_OFFSET; angle <= diff_angle; angle += abm ) {
222         if( m_MarkerOption == DIAL_MARKER_REDGREEN ) {
223             int a = int( angle + ANGLE_OFFSET ) % 360;
224             if( a > 180 ) GetGlobalColor( _T("DASHR"), &cl );
225             else if( ( a > 0 ) && ( a < 180 ) ) GetGlobalColor( _T("DASHG"), &cl );
226             else
227                 GetGlobalColor( _T("DASHF"), &cl );
228 
229             pen.SetColour( cl );
230             dc->SetPen( pen );
231         }
232 
233         double size = 0.92;
234         if( offset % m_MarkerOffset ) {
235             size = 0.96;
236         }
237         offset++;
238 
239         dc->DrawLine( m_cx + ( (m_radius-1) * size * cos( deg2rad( angle ) ) ),
240                 m_cy + ( (m_radius-1) * size * sin( deg2rad( angle ) ) ),
241                 m_cx + ( (m_radius-1) * cos( deg2rad( angle ) ) ),
242                 m_cy + ( (m_radius-1) * sin( deg2rad( angle ) ) ) );
243     }
244     // We must reset pen color so following drawings are fine
245     if( m_MarkerOption == DIAL_MARKER_REDGREEN ) {
246         GetGlobalColor( _T("DASHF"), &cl );
247         pen.SetStyle( wxPENSTYLE_SOLID );
248         pen.SetColour( cl );
249         dc->SetPen( pen );
250     }
251 }
252 
DrawLabels(wxGCDC * dc)253 void DashboardInstrument_Dial::DrawLabels(wxGCDC* dc)
254 {
255       if (m_LabelOption == DIAL_LABEL_NONE)
256             return;
257 
258       wxPoint TextPoint;
259       wxPen pen;
260       wxColor cl;
261       GetGlobalColor(_T("DASHF"), &cl);
262 
263 #ifdef __WXMSW__
264       wxSize size = GetClientSize();
265       //        Create a new bitmap for this method graphics
266       wxBitmap tbm( size.x, size.y, -1 );
267       wxMemoryDC tdc( tbm );
268 
269       wxColour cback;
270       GetGlobalColor( _T("DASHB"), &cback );
271       tdc.SetBackground( cback );
272       tdc.Clear();
273       tdc.SetFont(*g_pFontSmall);
274       tdc.SetTextForeground(cl);
275 #endif
276 
277       dc->SetFont(*g_pFontSmall);
278       dc->SetTextForeground(cl);
279 
280       int diff_angle = m_AngleStart + m_AngleRange - ANGLE_OFFSET;
281       // angle between markers
282       double abm = m_AngleRange * m_LabelStep / (m_MainValueMax - m_MainValueMin);
283       // don't draw last value, it's already done as first
284       if (m_AngleRange == 360) diff_angle -= abm;
285 
286       int offset = 0;
287       int value = m_MainValueMin;
288       int width, height;
289       for(double angle = m_AngleStart - ANGLE_OFFSET; angle <= diff_angle; angle += abm)
290       {
291             wxString label = (m_LabelArray.GetCount() ? m_LabelArray.Item(offset) : wxString::Format(_T("%d"), value));
292 #ifdef __WXMSW__
293             if( g_pFontSmall->GetPointSize() <= 12 )
294               tdc.GetTextExtent(label, &width, &height, 0, 0, g_pFontSmall);
295             else
296 #endif
297               dc->GetTextExtent(label, &width, &height, 0, 0, g_pFontSmall);
298 
299             double halfW = width / 2;
300             if (m_LabelOption == DIAL_LABEL_HORIZONTAL)
301             {
302                   double halfH = height / 2;
303                   //double delta = sqrt(width*width+height*height);
304                   double delta = sqrt(halfW*halfW+halfH*halfH);
305                   TextPoint.x = m_cx + ((m_radius * 0.90) - delta) * cos(deg2rad(angle)) - halfW;
306                   TextPoint.y = m_cy + ((m_radius * 0.90) - delta) * sin(deg2rad(angle)) - halfH;
307 
308 #ifdef __WXMSW__
309                   if( g_pFontSmall->GetPointSize() <= 12 )
310                     tdc.DrawText(label, TextPoint);
311                   else
312 #endif
313                     dc->DrawText(label, TextPoint);
314 
315 
316             }
317             else if (m_LabelOption == DIAL_LABEL_ROTATED)
318             {
319                   // The coordinates of dc->DrawRotatedText refer to the top-left corner
320                   // of the rectangle bounding the string. So we must calculate the
321                   // right coordinates depending of the angle.
322                   // Move left from the Marker so that the position is in the Middle of Text
323                   long double tmpangle = angle - rad2deg(asin(halfW / (0.90 * m_radius)));
324                   TextPoint.x = m_cx + m_radius * 0.90 * cos(deg2rad(tmpangle));
325                   TextPoint.y = m_cy + m_radius * 0.90 * sin(deg2rad(tmpangle));
326 
327 #ifdef __WXMSW__
328                  if( g_pFontSmall->GetPointSize() <= 12 )
329                      tdc.DrawRotatedText(label, TextPoint, -90 - angle);
330                  else
331 #endif
332                      dc->DrawRotatedText(label, TextPoint, -90 - angle);
333 
334             }
335             offset++;
336             value += m_LabelStep;
337       }
338 
339 #ifdef __WXMSW__
340       tdc.SelectObject( wxNullBitmap );
341 
342       if( g_pFontSmall->GetPointSize() <= 12 )
343             dc->DrawBitmap(tbm, 0, 0, false);
344 #endif
345 
346 }
347 
DrawBackground(wxGCDC * dc)348 void DashboardInstrument_Dial::DrawBackground(wxGCDC* dc)
349 {
350       // Nothing to do here right now, will be overwritten
351       // by child classes if required
352 }
353 
DrawData(wxGCDC * dc,double value,wxString unit,wxString format,DialPositionOption position)354 void DashboardInstrument_Dial::DrawData(wxGCDC* dc, double value,
355             wxString unit, wxString format, DialPositionOption position)
356 {
357       if (position == DIAL_POSITION_NONE)
358             return;
359 
360       dc->SetFont(*g_pFontLabel);
361       wxColour cl;
362       GetGlobalColor(_T("DASHF"), &cl);
363       dc->SetTextForeground(cl);
364 
365       wxSize size = GetClientSize();
366 
367       wxString text;
368       if(!std::isnan(value))
369       {
370           if (unit == _T("\u00B0"))
371                text = wxString::Format(format, value)+DEGREE_SIGN;
372           else if (unit == _T("\u00B0L")) // No special display for now, might be XX°< (as in text-only instrument)
373                text = wxString::Format(format, value)+DEGREE_SIGN;
374           else if (unit == _T("\u00B0R")) // No special display for now, might be >XX°
375                text = wxString::Format(format, value)+DEGREE_SIGN;
376           else if (unit == _T("\u00B0T"))
377                text = wxString::Format(format, value)+DEGREE_SIGN+_T("T");
378           else if (unit == _T("\u00B0M"))
379                text = wxString::Format(format, value)+DEGREE_SIGN+_T("M");
380           else if (unit == _T("N")) // Knots
381                text = wxString::Format(format, value)+_T(" Kts");
382           else
383                text = wxString::Format(format, value)+_T(" ")+unit;
384       }
385       else
386            text = _T("---");
387 
388       int width, height;
389       dc->GetMultiLineTextExtent(text, &width, &height, NULL, g_pFontLabel);
390 
391       wxRect TextPoint;
392       TextPoint.width = width;
393       TextPoint.height = height;
394       switch (position)
395       {
396             case DIAL_POSITION_NONE:
397                   // This case was already handled before, it's here just
398                   // to avoid compiler warning.
399                   return;
400             case DIAL_POSITION_INSIDE:
401             {
402                   TextPoint.x = m_cx - (width / 2) - 1;
403                   TextPoint.y = (size.y * .75) - height;
404                   GetGlobalColor(_T("DASHL"), &cl);
405                   int penwidth = size.x / 100;
406                   wxPen* pen = wxThePenList->FindOrCreatePen( cl, penwidth, wxPENSTYLE_SOLID );
407                   dc->SetPen( *pen );
408                   GetGlobalColor(_T("DASHB"), &cl);
409                   dc->SetBrush(cl);
410                   // There might be a background drawn below
411                   // so we must clear it first.
412                   dc->DrawRoundedRectangle(TextPoint.x-2, TextPoint.y-2, width+4, height+4, 3);
413                   break;
414             }
415             case DIAL_POSITION_TOPLEFT:
416                   TextPoint.x = 0;
417                   TextPoint.y = m_TitleHeight;
418                   break;
419             case DIAL_POSITION_TOPRIGHT:
420                   TextPoint.x = size.x-width-1;
421                   TextPoint.y = m_TitleHeight;
422                   break;
423             case DIAL_POSITION_BOTTOMLEFT:
424                   TextPoint.x = 0;
425                   TextPoint.y = size.y-height;
426                   break;
427             case DIAL_POSITION_BOTTOMRIGHT:
428                   TextPoint.x = size.x-width-1;
429                   TextPoint.y = size.x-height;
430                   break;
431       }
432 
433      wxColour c2;
434      GetGlobalColor( _T("DASHB"), &c2 );
435      wxColour c3;
436      GetGlobalColor( _T("DASHF"), &c3 );
437 
438      wxStringTokenizer tkz( text, _T("\n") );
439       wxString token;
440 
441       token = tkz.GetNextToken();
442       while(token.Length()) {
443         dc->GetTextExtent(token, &width, &height, NULL, NULL, g_pFontLabel);
444 
445 #ifdef __WXMSW__
446         if( g_pFontLabel->GetPointSize() <= 12 ) {
447             wxBitmap tbm( width, height, -1 );
448             wxMemoryDC tdc( tbm );
449 
450             tdc.SetBackground( c2 );
451             tdc.Clear();
452             tdc.SetFont(*g_pFontLabel );
453             tdc.SetTextForeground( c3 );
454 
455             tdc.DrawText(token, 0, 0 );
456             tdc.SelectObject( wxNullBitmap );
457 
458             dc->DrawBitmap(tbm, TextPoint.x, TextPoint.y, false);
459         }
460         else
461 #endif
462             dc->DrawText(token, TextPoint.x, TextPoint.y );
463 
464 
465         TextPoint.y += height;
466         token = tkz.GetNextToken();
467       }
468 }
469 
DrawForeground(wxGCDC * dc)470 void DashboardInstrument_Dial::DrawForeground(wxGCDC* dc)
471 {
472       // The default foreground is the arrow used in most dials
473       wxColour cl;
474       GetGlobalColor(_T("DASH2"), &cl);
475       wxPen pen1;
476       pen1.SetStyle(wxPENSTYLE_SOLID);
477       pen1.SetColour(cl);
478       pen1.SetWidth(2);
479       dc->SetPen(pen1);
480       GetGlobalColor(_T("DASH1"), &cl);
481       wxBrush brush1;
482       brush1.SetStyle(wxBRUSHSTYLE_SOLID);
483       brush1.SetColour(cl);
484       dc->SetBrush(brush1);
485       dc->DrawCircle(m_cx, m_cy, m_radius / 8);
486 
487       dc->SetPen(*wxTRANSPARENT_PEN);
488 
489       GetGlobalColor(_T("DASHN"), &cl);
490       wxBrush brush;
491       brush.SetStyle(wxBRUSHSTYLE_SOLID);
492       brush.SetColour(cl);
493       dc->SetBrush(brush);
494 
495       /* this is fix for a +/-180° round instrument, when m_MainValue is supplied as <0..180><L | R>
496        * for example TWA & AWA */
497       double data;
498       if(m_MainValueUnit == _T("\u00B0L"))
499           data=360-m_MainValue;
500       else
501           data=m_MainValue;
502 
503       // The arrow should stay inside fixed limits
504       double val;
505       if (data < m_MainValueMin) val = m_MainValueMin;
506       else if (data > m_MainValueMax) val = m_MainValueMax;
507       else val = data;
508 
509       double value = deg2rad((val - m_MainValueMin) * m_AngleRange / (m_MainValueMax - m_MainValueMin)) + deg2rad(m_AngleStart - ANGLE_OFFSET);
510 
511       wxPoint points[4];
512       points[0].x = m_cx + (m_radius * 0.95 * cos(value - .010));
513       points[0].y = m_cy + (m_radius * 0.95 * sin(value - .010));
514       points[1].x = m_cx + (m_radius * 0.95 * cos(value + .015));
515       points[1].y = m_cy + (m_radius * 0.95 * sin(value + .015));
516       points[2].x = m_cx + (m_radius * 0.22 * cos(value + 2.8));
517       points[2].y = m_cy + (m_radius * 0.22 * sin(value + 2.8));
518       points[3].x = m_cx + (m_radius * 0.22 * cos(value - 2.8));
519       points[3].y = m_cy + (m_radius * 0.22 * sin(value - 2.8));
520       dc->DrawPolygon(4, points, 0, 0);
521 }
522 
523 /* Shared functions */
DrawCompassRose(wxGCDC * dc,int cx,int cy,int radius,int startangle,bool showlabels)524 void DrawCompassRose(wxGCDC* dc, int cx, int cy, int radius, int startangle, bool showlabels)
525 {
526       wxPoint pt, points[3];
527       wxString Value;
528       int width, height;
529       wxString CompassArray[] = {_("N"),_("NE"),_("E"),_("SE"),_("S"),_("SW"),_("W"),_("NW"),_("N")};
530 
531       dc->SetFont(*g_pFontSmall);
532 
533       wxColour cl;
534       wxPen* pen;
535       GetGlobalColor(_T("DASH2"), &cl);
536       pen = wxThePenList->FindOrCreatePen( cl, 1, wxPENSTYLE_SOLID );
537       wxBrush* b2 = wxTheBrushList->FindOrCreateBrush( cl );
538 
539       GetGlobalColor(_T("DASH1"), &cl);
540       wxBrush* b1 = wxTheBrushList->FindOrCreateBrush( cl );
541 
542       dc->SetPen(*pen);
543       dc->SetTextForeground(cl);
544       dc->SetBrush(*b2);
545 
546       int offset = 0;
547       for(double tmpangle = startangle - ANGLE_OFFSET;
548                         tmpangle < startangle + 360 - ANGLE_OFFSET; tmpangle+=90)
549       {
550             if (showlabels)
551             {
552                 Value = CompassArray[offset];
553                 dc->GetTextExtent(Value, &width, &height, 0, 0, g_pFontSmall);
554                 double x = width/2;
555                 long double anglefortext = tmpangle - rad2deg(asin((x/radius)));
556                 pt.x = cx + radius * cos(deg2rad(anglefortext));
557                 pt.y = cy + radius * sin(deg2rad(anglefortext));
558                 dc->DrawRotatedText(Value, pt.x, pt.y, -90 - tmpangle);
559                 Value = CompassArray[offset+1];
560                 dc->GetTextExtent(Value, &width, &height, 0, 0, g_pFontSmall);
561                 x = width/2;
562                 anglefortext = tmpangle - rad2deg(asin((x/radius))) + 45;
563                 pt.x = cx + radius * cos(deg2rad(anglefortext));
564                 pt.y = cy + radius * sin(deg2rad(anglefortext));
565                 dc->DrawRotatedText(Value, pt.x, pt.y, -135 - tmpangle);
566             }
567             points[0].x = cx;
568             points[0].y = cy;
569             points[1].x = cx + radius * 0.15 * cos(deg2rad(tmpangle));
570             points[1].y = cy + radius * 0.15 * sin(deg2rad(tmpangle));
571             points[2].x = cx + radius * 0.6 * cos(deg2rad(tmpangle+45));
572             points[2].y = cy + radius * 0.6 * sin(deg2rad(tmpangle+45));
573             dc->DrawPolygon(3, points, 0, 0);
574             points[1].x = cx + radius * 0.15 * cos(deg2rad(tmpangle+90));
575             points[1].y = cy + radius * 0.15 * sin(deg2rad(tmpangle+90));
576             dc->SetBrush(*b1);
577             dc->DrawPolygon(3, points, 0, 0);
578             points[2].x = cx + radius * 0.8 * cos(deg2rad(tmpangle));
579             points[2].y = cy + radius * 0.8 * sin(deg2rad(tmpangle));
580             points[1].x = cx + radius * 0.15 * cos(deg2rad(tmpangle+45));
581             points[1].y = cy + radius * 0.15 * sin(deg2rad(tmpangle+45));
582             dc->DrawPolygon(3, points, 0, 0);
583             points[2].x = cx + radius * 0.8 * cos(deg2rad(tmpangle+90));
584             points[2].y = cy + radius * 0.8 * sin(deg2rad(tmpangle+90));
585             dc->SetBrush(*b2);
586             dc->DrawPolygon(3, points, 0, 0);
587             offset += 2;
588       }
589 }
590 
DrawBoat(wxGCDC * dc,int cx,int cy,int radius)591 void DrawBoat( wxGCDC* dc, int cx, int cy, int radius )
592 {
593     // Now draw the boat
594     wxColour cl;
595     GetGlobalColor(_T("DASH2"), &cl);
596     wxPen* pen = wxThePenList->FindOrCreatePen( cl, 1, wxPENSTYLE_SOLID );
597     dc->SetPen( *pen );
598     GetGlobalColor(_T("DASH1"), &cl);
599     dc->SetBrush(cl);
600     wxPoint points[7];
601 
602 /*
603  *           0
604  *          /\
605  *         /  \
606  *        /    \
607  *     6 /      \ 1
608  *      |        |
609  *      |    X   |
610  *    5 |        | 2
611  *       \      /
612  *        \__ _/
613  *        4    3
614  */
615     points[0].x = cx;
616     points[0].y = cy - radius * .60; // a little bit longer than compass rose
617     points[1].x = cx + radius * .15;
618     points[1].y = cy - radius * .08;
619     points[2].x = cx + radius * .15;
620     points[2].y = cy + radius * .12;
621     points[3].x = cx + radius * .10;
622     points[3].y = cy + radius * .40;
623     points[4].x = cx - radius * .10;
624     points[4].y = cy + radius * .40;
625     points[5].x = cx - radius * .15;
626     points[5].y = cy + radius * .12;
627     points[6].x = cx - radius * .15;
628     points[6].y = cy - radius * .08;
629 
630     dc->DrawPolygon(7, points, 0, 0);
631 }
632 
633