Home c# How to make a waving rainbow flag?

How to make a waving rainbow flag?

Author

Date

Category

I added a timer to the form (Interval = 100 , Enabled = true ), then I wrote this code:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace LoveWins
{
  public partial class RainbowForm: Form
  {
    static List & lt; Color & gt; RainbowColors = new List & lt; Color & gt; {
      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 & lt; SolidBrush & gt; RainbowBrushes =
      RainbowColors.Select (c = & gt; new SolidBrush (c)). ToList ();
    float angle = 0;
    public RainbowForm ()
    {
      InitializeComponent ();
    }
    void lgbtFlagTimer_Tick (object sender, EventArgs e)
    {
      using (Graphics graphics = CreateGraphics ()) {
        graphics.FillRectangle (Brushes.White, ClientRectangle);
        graphics.RotateTransform (angle);
        angle + = 1f;
        for (int i = 0; i & lt; RainbowBrushes.Count; i ++)
          graphics.FillRectangle (RainbowBrushes [i], 0, i * 80, 777, 80);
      }
    }
  }
}

My flag is turning, but this is not at all what we need. I don’t understand in any way how to make the flag fly in waves, as is usually the case for drawing flags. Graphics has all sorts of RotateTransform and ScaleTransform , but how to make a wave out of this is not clear. It should be something like this:

The flag is also flickering for some reason …


Answer 1, authority 100%

Here is my first attempt at splines. It doesn’t look very good, but I’ll try to improve it.

The root part is this:

void NewPosition ()
{
  firstPositionTarget = new PointF ((float) (rnd.NextDouble () * 100 + 50),
                   (float) (rnd.NextDouble () * 50 - 25));
  positions.Insert (0, new PointF (0f, 0f));
}
void UpdatePositions ()
{
  for (int i = positions.Count - 1; i & gt; = 0; i--)
  {
    var x = positions [i] .X + 10;
    if (x & gt; = ClientSize.Width + 200)
    {
      positions.RemoveAt (i);
    }
    else if (i & gt; 0)
    {
      positions [i] = new PointF (x, positions [i] .Y);
    }
    else if (x & lt; firstPositionTarget.X)
    {
      positions [i] = new PointF (x, firstPositionTarget.Y *
                       (x / firstPositionTarget.X));
    }
    else
    {
      positions [i] = new PointF (x, firstPositionTarget.Y);
      // add new point
      NewPosition ();
    }
  }
  if (positions.Count == 0 || positions.Max (p = & gt; p.X) & lt; ClientSize.Width)
    positions.Add (new PointF (ClientSize.Width + 200, 0));
}

This is the calculation of the spline anchor point positions. In fact, the new point is chosen at random so far, which makes the picture not very believable.

Rendering:

void germanFlagTimer_Tick (object sender, EventArgs e)
{
  UpdatePositions ();
  using (Graphics graphics = Graphics.FromImage (offscreenBitmap))
  {
    graphics.SmoothingMode = SmoothingMode.HighQuality;
    graphics.FillRectangle (Brushes.White, ClientRectangle);
    var totalPositions =
      Enumerable.Range (1, GermanBrushes.Count + 1)
            .Select (n = & gt; n * WaveHeight)
            .Select (y = & gt; new [] {new PointF (0, y)}
                   .Concat (positions.Select (p = & gt; new PointF (p.X, p.Y + y)))
                   .ToArray ())
            .ToList ();
    for (int i = 0; i & lt; GermanBrushes.Count; i ++)
    { 
Graphicspath Path = New Graphicspath ();
      Path.addcurve (TotalPositions [i], Tension: 0.5F);
      Path.addline (TotalPositions [i] .last (), TotalPositions [i + 1] .last ());
      Path.addcurve (TotalPositions [i + 1] .Reverse (). Toarray (), Tension: 0.5F);
      Path.addline (TotalPositions [i + 1] .first (), TotalPositions [i] .first ());
      graphics.fillpath (germanbrushes [i], path);
    }
    Using (Graphics FormGraphics = Creategraphics ())
      FormGraphics.Drawimage (offscreenbitmap, clientRectangle);
  }
}

I remind you that it is enough to change the filling of the array with flowers.

Full code:

Public Partial Class Germanform: Form
{
  Const int waveheight = 80;
  const int lineheight = 80;
  Static List & LT; Color & GT; Germancolors = new list & lt; Color & GT; {
    Color.FromArgB (0x0a, 0x0a, 0x0d),
    Color.FromargB (0xc1, 0x12, 0x1c),
    Color.FromArgB (0xee, 0xc9, 0x00)
  };
  Static List & LT; SolidBrush & GT; Germanbrushes =.
    Germancolors.select (C = & GT; New SolidBrush (C)). Tolist ();
  Bitmap offscreenbitmap;
  Public GermanForm ()
  {
    Initializecomponent ();
    Clientsize = New Size (777, lineheight * germancolors.count + waveheight * 2);
    offscreenbitmap = new bitmap (clientsize.width, clientsize.height);
    Newposition ();
  }
  List & lt; PointF & gt; Positions = New List & lt; PointF & gt; ();
  Pointf FirstPositionTarget;
  Random RND = New Random ();
  void newposition ()
  {
    firstpositionTarget = New PointF ((Float) (RND.NEXTDOUBLE () * 100 + 50),
                     (Float) (rnd.nextDouble () * 50 - 25));
    Positions.insert (0, New PointF (0F, 0F));
  }
  const float step = 10;
  void updatepositions ()
  {
    for (int i = positions.count - 1; i & gt; = 0; i--)
    {
      var X = Positions [i] .x + Step;
      if (x & gt; = clientsize.width + 200)
        Positions.Removeat (I);
      ELSE.
      {
        if (I & GT; 0)
        {
          Positions [i] = New PointF (X, Positions [i] .y);
        }
        ELSE If (x & lt; firstpositiontarget.x)
        {
          Positions [i] = New PointF (x, firstpositiontarget.y * (x / firstpositiontarget.x));
        }
        ELSE.
        {
          Positions [i] = New PointF (x, firstpositionTarget.y);
          // Add New Point
          Newposition ();
        }
      }
    }
    if (positions.count == 0 || positions.max (P = & gt; p.x) & lt; clientsize.width)
      Positions.add (New PointF (Clientsize.width + 200, 0));
  }
  Void GermanFlagTimer_Tick (Object Sender, Eventargs E)
  {
    UpdatePositions ();
    Using (Graphics Graphics = GRAPHICS.FromImage (offscreenBitmap))
    {
      graphics.smoothingmode = smoothingmode.highquality;
      graphics.fillrectangle (brushes.white, clientRectangle);
      var TotalPositions =
        Enumerable.Range (1, germanbrushes.count + 1)
             .Select (n = & gt; n * waveheight)
             .Select (y = & gt; new [] {new pointf (0, y)}
                     .Concat (Positions.Select (P = & GT; New PointF (P.x, P.Y + Y))))
                     .Toarray ())
             .Tolist ();
      for (int i = 0; i & lt; germanbrushes.count; i ++)
      {
        Graphicspath Path = New Graphicspath ();
        Path.addcurve (TotalPositions [i], Tension: 0.5F);
        Path.addline (TotalPositions [i] .last (), TotalPositions [i + 1] .last ());
        Path.addcurve (TotalPositions [i + 1] .Reverse (). Toarray (), Tension: 0.5F);
        Path.addline (TotalPositions [i + 1] .first (), TotalPositions [i] .first ());
        graphics.fillpath (germanbrushes [i], path);
      }
      Using (Graphics FormGraphics = Creategraphics ())
        FormGraphics.Drawimage (offscreenbitmap, clientRectangle); 
}
  }
}

Answer 2, Authority 86%

“Fundamental splines” some muddy and hard-managed, and understandable Bezier curves for some reason can only be drawn, but you can not pour the area limited by them (or I did not find a way), so that this example will come down and the sinus and polygons.

Take the waveform or just sinus:

math.sin (x / 100f) * Waveheight / 2f

or sinus sum:

(math.sin (x / 100f) + math.sin (x / 70f)) * Waveheight / 4f

And then just build a polygon by points (Y0 is 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 & lt; 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 render each wave:

for (int i = 0; i & lt; rainbowcolors.count; i ++) {
  Graphics.Fillpolygon (Rainbowbrushes [i], Points);
  For (int j = 0; j & lt; points.length; j ++)
    POINTS [J] .Y + = lineHeight;
}

To the animation does not “flicker”, you can draw on an extra-screen bitmap and copy to the form at once the entire finished picture. Otherwise, the realistic figure of the axis drawn may 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)) {
    // ...
    // Draw on Graphics
    // ...
    Using (Graphics FormGraphics = Creategraphics ())
      FormGraphics.Drawimage (offscreenbitmap, clientRectangle);
  }
}

Full example:

using system;
Using System.Collections.Genic;
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 & LT; Color & GT; RainbowColors = New List & LT; Color & GT; {
      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 & LT; SolidBrush & GT; Rainbowbrushes =.
      Rainbowcolors.select (C = & GT; 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 & lt; 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 & lt; rainbowcolors.count; i ++) { 
Graphics.Fillpolygon (Rainbowbrushes [i], Points);
           For (int j = 0; j & lt; 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);
     }
   }
}

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions