Hello all, I'm trying to approximate a sine wave using bezier curves (for rendering speed over drawing many straight lines).

I'm trying to follow the non-C# code specified down the page at:
http://commons.wikimedia.org/wiki/File:Harmonic_partials_on_strings.svg

// Produces a sine path as flat point array {PT, PT[3], PT[3], ...}
private static List<PointF> SineWavePath(float x, float y, float width, float amp, float num_half_waves)
{
	const float PI = 3.1415926535897f;
	const float XD = 0.261799388f;
	const float SQRT2 = 1.41421356f;
	const float Y1 = (2 * SQRT2) / 7 - 1 / 7;
	const float Y2 = (4 * SQRT2) / 7 - 2 / 7;
	const float Y3 = SQRT2 / 2;
	const float Y4 = (3 * SQRT2) / 7 + 2 / 7;

	float xmul = width / (num_half_waves * PI);
	float xd = XD * xmul;
	List<PointF> path = new List<PointF>();

	// Add the first point
	path.Add(new PointF(x, y));

	// Loop all the points
	for(int i = 1; i <= num_half_waves; i++)
	{
		// Add all of the points
		path.Add(new PointF(x + xd, y + amp * Y1));
		path.Add(new PointF(x + 2 * xd, y + amp * Y2));
		path.Add(new PointF(x + 3 * xd, y + amp * Y3));
		path.Add(new PointF(x + 4 * xd, y + amp * Y4));
		path.Add(new PointF(x + 5 * xd, y + amp));
		path.Add(new PointF(x + 6 * xd, y + amp));
		path.Add(new PointF(x + 7 * xd, y + amp));
		path.Add(new PointF(x + 8 * xd, y + amp * Y4));
		path.Add(new PointF(x + 9 * xd, y + amp * Y3));
		path.Add(new PointF(x + 10 * xd, y + amp * Y2));
		path.Add(new PointF(x + 11 * xd, y + amp * Y1));
		path.Add(new PointF(x + 12 * xd, y));

		x += (width / num_half_waves);

		// flip over vertically every half wave
		amp = amp * -1;
	}

	// Returnt he path
	return path;
}

And then rendering simply using

private void Form1_Paint(object sender, PaintEventArgs e)
{
	Graphics g = e.Graphics;
	Rectangle r = this.ClientRectangle;

	// Create the wave
	List<PointF> path = SineWavePath(r.Left, yCenter, r.Width, mAmplitude, (float)Math.Ceiling(r.Width / mWavelength));

	// Render
	g.DrawBeziers(mPen, path.ToArray());

	// Demonstrate where the control points are
	Font font = new Font(FontFamily.GenericSansSerif, 12);
	for(int i = 0; i < path.Count; i++)
	{
		g.DrawLine(Pens.Red, path[i], new PointF(path[i].X + 3, path[i].Y + 3));
		g.DrawLine(Pens.Red, path[i], new PointF(path[i].X - 3, path[i].Y + 3));
		if(i >= 1) g.DrawString((((i - 1) % 12) + 1).ToString(), font, Brushes.Black, path[i]);
	}
	font.Dispose();
}

However, this produces a jagged waveform that comes close, but does not approximate a sine wave.

See: http://www.actsoftheword.com/Image4.gif

Anybody see where my flaw is?

Recommended Answers

All 2 Replies

Just a thought

const float Y1 = (2 * SQRT2) / 7 - 1 / 7;
const float Y2 = (4 * SQRT2) / 7 - 2 / 7;
const float Y3 = SQRT2 / 2;
const float Y4 = (3 * SQRT2) / 7 + 2 / 7;

7 is not 7.0f
2 is not 2.0f
etc.

Duh. Of course, works like a charm. Thanks, I figured I was missing something simple.

const float Y1 = (2 * SQRT2) / 7.0f - 1.0f / 7.0f;
const float Y2 = (4 * SQRT2) / 7.0f - 2.0f / 7.0f;
const float Y3 = SQRT2 / 2.0f;
const float Y4 = (3 * SQRT2) / 7.0f + 2.0f / 7.0f;
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.