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 here. Hå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.
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.