Tuesday 11 February 2014

Irregular shapes and Bezier curves


Following on from the post at the weekend on Weird Faces I had a look at generating some hand-drawn shapes myself using Silverlight. First I had a look at Paper.js and noticed that there was some advice on hand-drawn rendering from the earlier Scriptographer references hereHåkan Lundgren put together some code to split a path into a number of segments. These can then be nudged around randomly and then smoothed to create a hand-drawn look like below:

Håkan advises that the sprinkles could be generated with a Halton Sequence-function. I need to take a look into that.







I had a bit of noodling around taking lines, breaking them apart into segments and then adjusting the points on the sequence, which was quite fun:



Random r = new Random();

PointCollection GetLine(Point p1, Point p2)
{
    int N = 10;

    double l = Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + 
               Math.Pow(p1.Y - p2.Y, 2));
 
    double dx = (p2.X - p1.X) / (N - 1);
    double dy = (p2.Y - p1.Y) / (N - 1);

    PointCollection points = new PointCollection();

    double a = 15;

    for (int i = 0; i < N; i++)
    {
        Point p = new Point();
        p.X = p1.X + (dx * i);
        p.Y = p1.Y + (dy * i);

        // wobble, not the ends
        if (i > 0 && i < N-1)
        {
            p.X += (r.NextDouble() * a) - (a / 2);
            p.Y += (r.NextDouble() * a) - (a / 2);
        }
        points.Add(p);
    }

    return points;
}

void DrawLine(PointCollection points, Color c)
{
    for (int i = 0; i < points.Count - 1; i++)
    {
        DrawLine(points[i], points[i + 1], c);
    }
}


This gave me some nice, but a bit jaggedy lines.

I then thought I could do the same with a circle, so had a go at that:



PointCollection GetCircle(Point p1, double rad)
{
    int N = 15;

    PointCollection points = new PointCollection();

    Point p0 = new Point();
    p0.X = (rad * Math.Cos(2 * Math.PI * N / (N + 1))) + p1.X;
    p0.Y = (rad * Math.Sin(2 * Math.PI * N / (N + 1))) + p1.Y;

    double a = 20;

    points.Add(p0);

    for (int i = 0; i < N; i++)
    {
        Point p = new Point();
        p.X = (rad * Math.Cos(2 * Math.PI * i / (N + 1))) + p1.X;
        p.Y = (rad * Math.Sin(2 * Math.PI * i / (N + 1))) + p1.Y;

        // wobble
        p.X += (r.NextDouble() * a) - (a / 2);
        p.Y += (r.NextDouble() * a) - (a / 2);
                
        points.Add(p);
    }

    points.Add(p0);

    return points;
}

Again, pretty neat and made some nice shapes, but I had the hunkering for some more and some smoothness, so dug into Bezier lines. When I get a chance this will be ideal for a little Gem, for now, I dug up some excellent posts:

  • This one goes through the basic WPF shapes as a good summary that can be easily referenced.
  • This one for a great run through of creating smooth curves.
I had a bit of play with the second article using the final example of a smooth curve, which I modified to create some bumpy circles which I then displayed in a pattern.


private PointCollection GetBumpyCircle(Point p)
{
    double dA = 8;
    double dR = 28;      // Radius of inside circle. 
    int iDegrees = 10;    // Step degrees.
    double dAngle;        // Step radians.

    // Total number of points (must be even).
    int iN = 360 / iDegrees;

    // Get points.
    double X = 0.0;
    double Y = 0.0;
    PointCollection pointsCurve = new PointCollection();
            
    for (int i = 0; i < 360; i += iDegrees)
    {
        dAngle = Math.PI * i / 180.0;
        // On outside circle.
        X = dR * Math.Cos(dAngle) + ((r.NextDouble() - 0.5) * dA) + p.X;
        Y = dR * Math.Sin(dAngle) + ((r.NextDouble() - 0.5) * dA) + p.Y;
        pointsCurve.Add(new Point(X, Y));
    }

    return pointsCurve;
}

The result is some fun little irregular shapes:

Certainly the basis for some more fun later on.... the Bezier article is definately worth a little more investigation for some future ideas.

No comments:

Post a Comment