-
Notifications
You must be signed in to change notification settings - Fork 598
/
Copy pathProgram.Drawings.cs
224 lines (191 loc) · 8.41 KB
/
Program.Drawings.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Iot.Device.LEDMatrix;
using Iot.Device.Graphics;
using System.Drawing;
using System.Numerics;
using static LedMatrixWeather.MathUtils;
namespace LedMatrixWeather
{
internal partial class Program
{
private static readonly Vector3 s_cloudsColor = new Vector3(0.3f, 0.3f, 0.3f);
private static float Line(Vector2 uv, float len)
{
if (uv.Y < 0)
{
return Math.Max(-uv.Y, Math.Abs(uv.X));
}
else if (uv.Y > len)
{
return Math.Max(uv.Y - len, Math.Abs(uv.X));
}
else
{
return Math.Abs(uv.X);
}
}
private static Vector3 Clock(Vector2 uv, DateTimeOffset time)
{
uv -= new Vector2(0.5f, 0.5f);
float len = uv.Length();
float outerRadius = 0.47f;
float outerRadiusDist = Math.Abs(len - outerRadius);
float outerCircle = 1.0f - smoothstep(0f, 0.025f, outerRadiusDist);
float innerRadius = 0.04f;
float innerRadiusDist = len - innerRadius;
float ftime = (float)time.Second + time.Millisecond / 1000f;
float secondsAngle = 2f * pi * ftime / 60f;
float minutesAngle = 2f * pi * (float)time.Minute / 60f + secondsAngle / 60f;
float hoursAngle = 2f * pi * (float)(time.Hour % 12) / 12f + minutesAngle / 60f;
float secondsLine = 1.0f - smoothstep(0f, 0.025f, Line(Rot(uv, secondsAngle), 0.4f));
float minutesLine = 1.0f - smoothstep(0f, 0.025f, Line(Rot(uv, minutesAngle), 0.35f));
float hoursLine = 1.0f - smoothstep(0f, 2f * 0.025f, Line(Rot(uv, hoursAngle), 0.2f));
const float dotsSize = 0.02f;
float extraDotsSize = 0.0f; // 0 means original size, 1 means double the size
#if TWIST_ON_TICK_TOCK
// this currently works but doesn't improve visual
// it needs a bit more experimenting to make it look better
// T = 2s because tick tock
float effectRatio = Math.Clamp((1 + 1.5f * (float)Math.Sin(2 * pi * ftime / 2.0f)) / 2f, 0, 1);
uv /= 1f - 0.25f * effectRatio;
len = uv.Length();
uv = Rot(uv, - len * effectRatio / 0.4f * 2 * pi / 6);
extraDotsSize = 0.32f * effectRatio;
#endif
int ticks = 12;
float tickSize = 1.0f / ticks;
float halfTickSize = tickSize / 2;
float tickDist = Math.Abs(mod(0.5f + ticks * (float)Math.Atan2(uv.Y, uv.X) / 2 / pi, 1.0f) - 0.5f) * 2 * pi / ticks * len;
float tickCircleDist = Math.Abs(len - 0.4f);
float dots = 1.0f - smoothstep(0f, dotsSize * (1 + extraDotsSize), Math.Max(tickDist, tickCircleDist));
return mix(
new Vector3(1, 0, 0),
new Vector3(Math.Max(dots, Math.Max(outerCircle, secondsLine)), minutesLine, hoursLine),
smoothstep(0f, 0.01f, innerRadiusDist));
}
private static Vector3 OpenWeatherIcon(Vector2 uv, string icon, float time)
{
uv -= new Vector2(0.5f, 0.5f);
return icon switch
{
"01d" or "01d.org" => IconSunny(uv, time),
"01n" => IconMoon(uv, time),
"02d" => IconPartiallySunny(uv, time),
// partially cloudy at night
"02n" => IconMoon(uv, time),
"03d" or // clouds day
"03n" or // clouds night
"04d" or // overcast clouds
"04n" or
"11d" or // with thunder
"11n" or
"13d" or // with snow
"13n" or
"50d" or // no clue what the picture represents but kinda looks like a cloud
"50n" => IconClouds(uv, time),
"09d" or "09n" or
"10d" or // with a bit of the sun
"10n" => IconRain(uv, time),
// Don't know the icon
// We're in Seattle so let's assume rain
_ => IconRain(uv, time),
};
}
private static Vector3 IconSunny(Vector2 uv, float time)
{
const int NumberOfRays = 10;
const float OuterRadius = 0.45f;
const float InnerRadius = 0.25f;
const float RayLength = OuterRadius - InnerRadius;
// spiral and rotate everything a bit
uv = Rot(uv, uv.Length() * 2 * 2 * pi / 10f * (float)Math.Sin(2 * pi * time / 9.0f) - time / 2.0f);
float angle = (float)Math.Atan2(uv.Y, uv.X) / 2 / pi * NumberOfRays;
// for soft rays: (float)Math.Sin(2 * pi * angle);
float rayShape = 2 * Math.Abs(mod(angle, 1.0f) - 0.5f);
float rayLen = RayLength * rayShape;
float radius = InnerRadius + rayLen;
float radiusDist = uv.Length() - radius;
return mix(
new Vector3(1, 1, 0),
new Vector3(0, 0, 0),
smoothstep(0f, 0.02f, radiusDist));
}
private static float Clouds(Vector2 uv, float time)
{
float r0 = 0.15f;
Vector2 p0 = new Vector2(-0.2f, 0.1f + 0.05f * (float)Math.Sin(2 * pi * time / 7f + 0.1f));
float c0 = (uv - p0).Length() - r0;
float r1 = 0.15f + 0.05f * (float)Math.Sin(2 * pi * time / 13f);
Vector2 p1 = new Vector2(0f, 0.08f * (float)Math.Sin(2 * pi * time / 5f + 0.7f));
float c1 = (uv - p1).Length() - r1;
float r2 = 0.15f;
Vector2 p2 = new Vector2(0.2f, 0.05f - 0.05f * (float)Math.Sin(2 * pi * time / 4f + 0.9f));
float c2 = (uv - p2).Length() - r2;
float clouds = Math.Min(Math.Min(c0, c1), c2);
return smoothstep(0f, 0.2f, clouds + 0.05f);
}
private static Vector3 IconClouds(Vector2 uv, float time)
{
float clouds = Clouds(uv, time);
return mix(
s_cloudsColor,
new Vector3(0, 0, 0),
clouds);
}
private static Vector3 Rain(Vector2 uv, float time)
{
if (uv.Y < -0.1 || uv.X <= -0.4 || uv.X >= 0.4)
{
return new Vector3(0, 0, 0);
}
uv.Y -= time / 3f;
float dropSpeed = 2 + 0.5f * (float)Math.Sin(2 * pi * uv.X * 77f);
float dropNoise = 11 * uv.X + (float)Math.Sin(2 * pi * uv.X * 100f);
float rain = smoothstep(0f, 0.05f,
(float)Math.Sin(2 * pi * (dropNoise + dropSpeed * uv.Y)) - 0.9f);
return mix(
new Vector3(0, 0, 0),
new Vector3(0, 0, 0.3f),
rain);
}
private static Vector3 IconRain(Vector2 uv, float time)
{
float clouds = Clouds(uv - new Vector2(0f, -0.3f), time);
return mix(
s_cloudsColor,
Rain(uv, time),
clouds);
}
private static Vector3 IconMoon(Vector2 uv, float time)
{
uv -= new Vector2(0.3f, 0.0f);
uv = Rot(uv, 2 * pi / 128 * (float)Math.Sin(2 * pi * time / 3f));
uv += new Vector2(0.35f, 0.0f);
float r0 = 0.3f;
Vector2 p0 = new Vector2(0.0f, 0.0f);
float c0 = (uv - p0).Length() - r0;
float r1 = 0.35f;
Vector2 p1 = new Vector2(0.20f, 0.0f);
float c1 = (uv - p1).Length() - r1;
float moon = Math.Max(c0, -c1);
return mix(
new Vector3(0.5f, 0.5f, 0.5f),
new Vector3(0, 0, 0),
smoothstep(0f, 0.07f, moon));
}
private static Vector3 IconPartiallySunny(Vector2 uv, float time)
{
float clouds = Clouds(uv * 0.85f - new Vector2(0f, 0.15f), time);
return mix(
s_cloudsColor,
IconSunny(uv, time),
clouds) * 0.6f;
}
}
}