4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "ThermalAssistantRenderer.hpp"
25 #include "Util/Macros.hpp"
26 #include "Util/Clamp.hpp"
27 #include "NMEA/Attitude.hpp"
28 #include "NMEA/Derived.hpp"
29 #include "Screen/Canvas.hpp"
30 #include "Screen/Layout.hpp"
31 #include "Formatter/UserUnits.hpp"
32 #include "Language/Language.hpp"
33 #include "Look/ThermalAssistantLook.hpp"
36 #include "Screen/OpenGL/Scope.hpp"
40 ThermalAssistantRenderer::LiftPoints::GetAverage() const
42 RasterPoint avg
= { 0, 0 };
44 for (auto it
= begin(), it_end
= end(); it
!= it_end
; ++it
) {
55 ThermalAssistantRenderer::ThermalAssistantRenderer(const ThermalAssistantLook
&_look
,
56 unsigned _padding
, bool _small
)
60 direction(Angle::Zero()) {}
63 ThermalAssistantRenderer::Update(const AttitudeState
&attitude
,
64 const DerivedInfo
&derived
)
66 direction
= attitude
.heading
;
67 circling
= (CirclingInfo
)derived
;
68 vario
= (VarioInfo
)derived
;
72 ThermalAssistantRenderer::CalculateMaxLift() const
74 return std::max(fixed(1),
75 *std::max_element(vario
.lift_database
.begin(),
76 vario
.lift_database
.end()));
80 ThermalAssistantRenderer::CalculateLiftPoints(LiftPoints
&lift_points
,
83 Angle angle
= -direction
;
84 constexpr Angle delta
= Angle::FullCircle() / unsigned(std::tuple_size
<LiftDatabase
>());
86 for (unsigned i
= 0; i
< lift_points
.size(); i
++, angle
+= delta
) {
87 auto sincos
= angle
.SinCos();
88 auto scale
= NormalizeLift(vario
.lift_database
[i
], max_lift
) * fixed(radius
);
90 lift_points
[i
].x
= (int)(sincos
.second
* scale
);
91 lift_points
[i
].y
= (int)(sincos
.first
* scale
);
93 if (!circling
.TurningLeft()) {
94 lift_points
[i
].x
*= -1;
95 lift_points
[i
].y
*= -1;
98 lift_points
[i
].x
+= mid
.x
;
99 lift_points
[i
].y
+= mid
.y
;
104 ThermalAssistantRenderer::NormalizeLift(fixed lift
, fixed max_lift
)
106 lift
= (lift
+ max_lift
) / Double(max_lift
);
107 return Clamp(lift
, fixed(0), fixed(1));
111 ThermalAssistantRenderer::PaintRadarPlane(Canvas
&canvas
) const
113 canvas
.Select(look
.plane_pen
);
115 PixelScalar x
= mid
.x
+ (circling
.TurningLeft() ? radius
: -radius
);
117 canvas
.DrawLine(x
+ Layout::FastScale(small
? 5 : 10),
118 mid
.y
- Layout::FastScale(small
? 1 : 2),
119 x
- Layout::FastScale(small
? 5 : 10),
120 mid
.y
- Layout::FastScale(small
? 1 : 2));
122 mid
.y
- Layout::FastScale(small
? 3 : 6),
124 mid
.y
+ Layout::FastScale(small
? 3 : 6));
125 canvas
.DrawLine(x
+ Layout::FastScale(small
? 2 : 4),
126 mid
.y
+ Layout::FastScale(small
? 2 : 4),
127 x
- Layout::FastScale(small
? 2 : 4),
128 mid
.y
+ Layout::FastScale(small
? 2 : 4));
132 ThermalAssistantRenderer::PaintRadarBackground(Canvas
&canvas
, fixed max_lift
) const
134 canvas
.SelectHollowBrush();
136 canvas
.Select(look
.inner_circle_pen
);
137 canvas
.DrawCircle(mid
.x
, mid
.y
, radius
/ 2);
138 canvas
.Select(look
.outer_circle_pen
);
139 canvas
.DrawCircle(mid
.x
, mid
.y
, radius
);
144 canvas
.SetTextColor(COLOR_BLACK
);
145 canvas
.Select(look
.circle_label_font
);
146 canvas
.SetBackgroundColor(look
.background_color
);
147 canvas
.SetBackgroundOpaque();
149 TCHAR lift_string
[10];
150 FormatUserVerticalSpeed(max_lift
, lift_string
, ARRAY_SIZE(lift_string
));
151 PixelSize s
= canvas
.CalcTextSize(lift_string
);
152 canvas
.DrawText(mid
.x
- s
.cx
/ 2,
153 mid
.y
+ radius
- s
.cy
* 0.75,
156 FormatUserVerticalSpeed(fixed(0), lift_string
, ARRAY_SIZE(lift_string
));
157 s
= canvas
.CalcTextSize(lift_string
);
158 canvas
.DrawText(mid
.x
- s
.cx
/ 2,
159 mid
.y
+ radius
/ 2 - s
.cy
* 0.75,
162 canvas
.SetBackgroundTransparent();
166 ThermalAssistantRenderer::PaintPoints(Canvas
&canvas
,
167 const LiftPoints
&lift_points
) const
170 GLBlend
blend(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
171 #elif defined(USE_GDI)
175 canvas
.Select(look
.polygon_brush
);
176 canvas
.Select(look
.polygon_pen
);
177 canvas
.DrawPolygon(lift_points
.data(), lift_points
.size());
181 ThermalAssistantRenderer::PaintAdvisor(Canvas
&canvas
,
182 const LiftPoints
&lift_points
) const
184 canvas
.DrawLine(mid
, lift_points
.GetAverage());
188 ThermalAssistantRenderer::PaintNotCircling(Canvas
&canvas
) const
193 const TCHAR
* str
= _("Not Circling");
194 canvas
.Select(look
.overlay_font
);
195 PixelSize ts
= canvas
.CalcTextSize(str
);
196 canvas
.SetTextColor(look
.text_color
);
197 canvas
.DrawText(mid
.x
- (ts
.cx
/ 2), mid
.y
- (radius
/ 2), str
);
201 ThermalAssistantRenderer::UpdateLayout(const PixelRect
&rc
)
203 radius
= std::min(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
) / 2 - padding
;
204 mid
= rc
.GetCenter();
208 ThermalAssistantRenderer::Paint(Canvas
&canvas
)
210 fixed max_lift
= ceil(CalculateMaxLift());
212 PaintRadarBackground(canvas
, max_lift
);
213 if (!circling
.circling
) {
214 PaintNotCircling(canvas
);
218 LiftPoints lift_points
;
219 CalculateLiftPoints(lift_points
, max_lift
);
220 PaintPoints(canvas
, lift_points
);
221 PaintAdvisor(canvas
, lift_points
);
223 PaintRadarPlane(canvas
);