For some reason, the āFundamental splinesā are muddy and difficult to control, and understandable Bezier curves can only be drawn, but you cannot fill in the area bounded by them (or I havenāt found a way), so for this example a clumsy solution will come off on sines and polygons.
We take a waveform or just a sine:
Math.Sin(x / 100f) * WaveHeight / 2f
or the sum of sines:
(Math.Sin(x / 100f) + Math.Sin(x / 70f)) * WaveHeight / 4f
and then simply build the polygon by the points ( y0 used so that the flag is "attached" to the left edge):
float y0 = Wave(offset) - WaveHeight; int stride = 777 / Segments + 1; var points = new PointF[stride * 2]; for (int i = 0; i < stride; i++) { float x = i * Segments; points[i] = new PointF(x, Wave(x + offset) - y0); points[2 * stride - i - 1] = new PointF(x, Wave(x + offset) - y0 + LineHeight); }
and draw each wave:
for (int i = 0; i < RainbowColors.Count; i++) { graphics.FillPolygon(RainbowBrushes[i], points); for (int j = 0; j < points.Length; j++) points[j].Y += LineHeight; }
In order for the animation not to "flicker", you can draw on an offscreen bitmap and copy the entire finished picture onto the form at once. Otherwise, the actual image of the axis drawn can occur (and occurs) in the middle of the drawing process.
Bitmap offscreenBitmap = new Bitmap(width, height); void lgbtFlagTimer_Tick (object sender, EventArgs e) { using (Graphics graphics = Graphics.FromImage(offscreenBitmap)) { // ... // ŃŠøŃŃŠµŠ¼ на graphics // ... using (Graphics formGraphics = CreateGraphics()) formGraphics.DrawImage(offscreenBitmap, ClientRectangle); } }
Full example:
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Windows.Forms; namespace LoveWins { public partial class RainbowForm : Form { const int Segments = 30; const int WaveHeight = 80; const int LineHeight = 80; static List<Color> RainbowColors = new List<Color> { Color.FromArgb(0xE4, 0x03, 0x03), Color.FromArgb(0xFF, 0x8C, 0x00), Color.FromArgb(0xFF, 0xED, 0x00), Color.FromArgb(0x00, 0x80, 0x26), Color.FromArgb(0x00, 0x4D, 0xFF), Color.FromArgb(0x75, 0x07, 0x87), }; static List<SolidBrush> RainbowBrushes = RainbowColors.Select(c => new SolidBrush(c)).ToList(); int offset; Bitmap offscreenBitmap; public RainbowForm () { InitializeComponent(); ClientSize = new Size(777, LineHeight * 6 + WaveHeight * 2); offscreenBitmap = new Bitmap(ClientSize.Width, ClientSize.Height); } void lgbtFlagTimer_Tick (object sender, EventArgs e) { using (Graphics graphics = Graphics.FromImage(offscreenBitmap)) { graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.FillRectangle(Brushes.White, ClientRectangle); float y0 = Wave(offset) - WaveHeight; int stride = 777 / Segments + 1; var points = new PointF[stride * 2]; for (int i = 0; i < stride; i++) { float x = i * Segments; points[i] = new PointF(x, Wave(x + offset) - y0); points[2 * stride - i - 1] = new PointF(x, Wave(x + offset) - y0 + LineHeight); } for (int i = 0; i < RainbowColors.Count; i++) { graphics.FillPolygon(RainbowBrushes[i], points); for (int j = 0; j < points.Length; j++) points[j].Y += LineHeight; } using (Graphics formGraphics = CreateGraphics()) formGraphics.DrawImage(offscreenBitmap, ClientRectangle); offset -= 10; } } float Wave (float x) { //return (float)(Math.Sin(x / 100f) * WaveHeight / 2f); return (float)((Math.Sin(x / 100f) + Math.Sin(x / 70f)) * WaveHeight / 4f); } } }