开发者

Simulate a spray

How can i simulate a spray like windows paint ? i think it create points random , what 开发者_运维知识库is your opinion?


Yes, I would say it colors random pixels within a certain radius of the selection point. There's also probably a time delay between the coloring of one pixel and the other, because machines today are fast enough to be able to color every possible pixel (As long as the radius is small) before you could let go of the mouse button.

Also, I think the algorithm that Paint uses can select a pixel to paint even if it already has been painted, since sometimes you can end up with a painted circle with a few unpainted pixels inside.


The pattern for spray paint would be semi-random. If you get out a can of Krylon and slowly spray a line on a wall, you end up with a wide solid line that fades out to the background with a gradient around the edges. Spray in one spot for ten seconds, and you get a big dot in the center in which the color is fully saturated, with a radial gradient to the background.

So- your variables for simulation include:

  • Time holding the "sprayer" (mouse button)
  • Motion of the "can" (mouse)
  • Speed of the "can" (fast moves make a light, unsaturated line. Slow moves make a thick, saturated line with a gradient)
  • spread pattern: is the spray focused like an airbrush, or big like a spray can?
  • "Distance": How far away is the "sprayer" from the "canvas"?


You have received a number of answers pointing you in the right direction to start handling the user experience of the spray effect. Based on your reponse to my comment you also need an algorithm for generating the random points within the radius.

There are a number of ways to do this, and probably the most obvious would be to use polar coordinates to select the random point and then transform the polar coordinate to a cartesian (x,y) coordinate to render the pixel. Here is a simple example of this approach. To keep things simple, I have just drawn a simple 1x1 ellipse for each point.

private Random _rnd = new Random();
private void Form1_MouseDown(object sender, MouseEventArgs e)
{      
  int radius = 15;

  using (Graphics g = this.CreateGraphics())
  {
    for (int i = 0; i < 100; ++i)
    {
      // Select random Polar coordinate
      // where theta is a random angle between 0..2*PI
      // and r is a random value between 0..radius
      double theta = _rnd.NextDouble() * (Math.PI * 2);
      double r = _rnd.NextDouble() * radius;

      // Transform the polar coordinate to cartesian (x,y)
      // and translate the center to the current mouse position
      double x = e.X + Math.Cos(theta) * r;
      double y = e.Y + Math.Sin(theta) * r;

      g.DrawEllipse(Pens.Black, new Rectangle((int)x - 1, (int)y - 1, 1, 1));
    }
  }
}

Alternatively, you can randomly select x,y coordinates from the rectangle that fits the spray circle and using the circle equation r^2 = x^2 + y^2 test the point to determine if it lies inside the circle, if it does you randomly select another point and test again until you have a point that lies within the circle. Here is a quick sample of this approach

private Random _rnd = new Random();
private void Form1_MouseDown(object sender, MouseEventArgs e)
{      
  int radius = 15;
  int radius2 = radius * 2;

  using (Graphics g = this.CreateGraphics())
  {
    double x;
    double y;

    for (int i = 0; i < 100; ++i)
    {          
      do 
      {
        // Randomy select x,y so that 
        // x falls between -radius..radius
        // y falls between -radius..radius
        x = (_rnd.NextDouble() * radius2) - radius;
        y = (_rnd.NextDouble() * radius2) - radius;

        // If x^2 + y^2 > r2 the point is outside the circle
        // and a new point needs to be selected
      } while ((x*x + y*y) > (radius * radius));

      // Translate the point so that the center is at the mouse
      // position
      x += e.X;
      y += e.Y;

      g.DrawEllipse(Pens.Black, new Rectangle((int)x - 1, (int)y - 1, 1, 1));
    }
  }
}


You can create a spray pattern of various intensities by sampling some number (related to the desired intensity and spread) of polar coordinates. To do this, determine a random polar coordiate (ρ, θ) for each sample by:

ρ sampled from N(0, 1): Use a Normal (Gaussian) distribution for the distance from the exact center of your spray pattern. I don't recall if there's a normal variate generator in the .NET library. If there isn't, you can create one from a U(0, 1) generator.

θ sampled from U(0, π): Sample the angular component from the Uniform Continuous Distribution. Without loss of performance or generality, you could instead sample on U(nπ, mπ) for n < m, but U(0, π) will probably be fine for what you need.

The Cartesian coordinates of each sample are give by (Tx + Sxρ cos θ, Ty + Syρ sin θ) where (Tx, Ty) is the center of the spray pattern you want to create; Sx and Sy are the spread factors you want to have in the x and y directions respectively.


Try using the timer

public partial class Form1 : Form
{
    int Radious = 5;
    Random _rnd = new Random();
    Timer T = new Timer();
    int InterVal = 1000;
    MouseEventArgs MEA = null;
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        T.Tick += (O, E) =>
        {
            StartSpray();
        };
        this.MouseDown += (O, E) =>
        {
            MEA = E;
            T.Interval = InterVal;
            T.Start();

         };
        this.MouseUp += (O, E) =>
        {
            T.Stop();
        };
    }
    private void StartSpray()
    {
        Point P = DrawPoint(Radious, MEA.X, MEA.Y);
        // Draw the point on any graphics area you can add the color or anything else
    }
    private Point DrawPoint(int Radious, int StatX, int StartY)
    {
        double theta = _rnd.NextDouble() * (Math.PI * 2);
        double r = _rnd.NextDouble() * Radious;
        Point P = new Point { X = StatX + Convert.ToInt32(Math.Cos(theta) * r), Y = StartY + Convert.ToInt32(Math.Sin(theta) * r) };
        return P;
    }      
}

please modify the Interval and the radius.


I think it's hard to find a sample on C#. Below I present a way to start your journey on this. Here I am using a texture brush.

private void Button1_Click(System.Object sender, System.EventArgs e)
{
    try
    {
        Bitmap image1 = (Bitmap)Image.FromFile(@"C:\temp\mybrush.bmp", true);

        TextureBrush t = new TextureBrush(image1);
        t.WrapMode = System.Drawing.Drawing2D.WrapMode.Tile;
        Graphics formGraphics = this.CreateGraphics();
        formGraphics.FillEllipse(t, new RectangleF(90.0F, 110.0F, 100, 100));
        formGraphics.Dispose();

    }
    catch (System.IO.FileNotFoundException)
    {
        MessageBox.Show("Image file not found!");
    }

}

as Jesse said, I think you should find an algorithm to spread random pixels.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜