- Table of Contents
- .NET Book Recommendations
- What Is .NET?
- The Microsoft .NET Framework
- The Common Language Runtime (CLR), the Common Type System (CTS), and the Common Language Specification (CLS)
- .NET Framework Class Library
- Visual Studio .NET
- .NET Enterprise Servers and .NET My Services
- .NET Compliant Languages
- C#
- Visual Basic .NET (VB .NET)
- ASP.NET
- XML Web Services
- ADO.NET
- XML.NET
- Windows Forms
- Why .NET?
- Displaying Errors with the Error Provider
- COM Interoperability
- Comparing Java and .NET
- Calling Unmanaged Code
- .NET Application Security
- Code Access Security
- .NET Standards Support
- Numeric Types in the .NET Framework
- Working with Strings
- Formatting Strings
- Trimming Character Strings
- Comparing Strings in .NET 2.0
- Arrays and Collections
- Arrays as Class Members
- Sorting a Multi-Dimensional Array
- Sorting a Multi-Dimensional Array with LINQ
- File I/O (System.IO)
- Working with File Names
- Using the File System
- Working with Files and Directories
- Monitoring the File System
- Working with Streams
- Working with Text Encodings
- Working with Date and Time
- Extending the DateTime Class
- Fun with Dates
- Exceptions
- Delegates
- Events
- Asynchronous Programming
- Asynchronous File I/O
- Timers
- Random Numbers
- Cryptographically Secure Random Numbers
- Serialization
- MultiThreading (System.Threading)
- Multi-Threading Overview
- The Managed Thread Pool
- Managed Threading
- Thread Synchronization
- Synchronizing Data Access
- Trace Debugging
- Tracing in .NET 2.0
- ASP.NET Trace
- Validating User Input in ASP.NET Web Pages
- Event Logging
- Monitoring Application Performance
- Accessing the Registry
- Accessing Environment Information
- Environment Variables in .NET 2.0
- Managing Windows Forms Applications
- Working with Email
- Working with Graphics
- Animating a Background
- Working with Images
- Drawing Cycloid Curves
- Simulating the Spirograph
- Building International Web Applications
- .NET Compact Framework
- Mobile Web Development with ASP.NET
- Speech Technologies
- Microsoft MapPoint Web Service
- Working with Typed DataSets
- Using Relationships in DataSets
- DataColumn Expressions
- Playing Simple Sounds
- Playing Sounds with .NET 2.0
- Returning an Image in a Web Page
- RSS
- Best Practices Project Structure
- Best Practices Application Blocks
- The Data Access Application Block
- The Exception Management Application Block
- Best Practices — Performance
- Best Practices — Performance and Scalability
- Best Practices - Testing
- Reading the Tea Leaves, 2005
- Predictions: A Look Back at 2005, and a Look Ahead to 2006
- .NET Downloads
- Application Deployment Overview
- Application Deployment — Versioning
- Application Deployment — Version Policy
- Application Deployment — Packaging and Distribution
- .NET Remoting Overview
- A Remoting Demonstration
- Remoting Configuration
- Remoting: Lifetimes and Leases
- Remoting: Other Issues
- Attributes
- Writing Custom Attributes
- Accessing Attributes in Code
- Reflection
- Class Design: Inheritance, Interface, or Composition?
- The TriTryst Game
- Console Applications in .NET 2.0
- New File I/O Methods in .NET 2.0
- Building Projects with MSBuild
- Unmanaged Callbacks in .NET 2.0
- Timer Troubles
- Non-Rectangular Windows Forms
- Windows Forms Transparency
- 10 Things I Hate About Visual Basic
- 10 Things I Hate About C#
- Background Processing with Idle Time
- Scaling Windows Forms
- Reading and Writing Binary Data
- New Memory Management Functions in .NET 2.0
- Compatibility Between .NET 1.1 and .NET 2.0
- Managed Debugging Assistants in .NET 2.0
- XDir: A Program for Viewing Directory Sizes
- The Microsoft.VisualBasic Namespace
- Operator Overloading
- Working with GPS Data
- Hidden Visual Studio Tools
- .NET 3.0
- The .NET 2.0 Stopwatch Class
- Nullable Types
- Drawing Rotated Text
- Unsafe Code
- Other .NET Languages
- Compiler Directives
- Safe Handles
- Predictions, 2007 Edition
- New Features in C# 3.0
- Generics
- Network Client Programming
- On the Misuse of Exceptions
- Maximum Object Size in .NET
- More on Maximum Object Sizes
- Keyed Collection Memory Limitations
- Matching String Endings
- Allocating Small Data Structures
- Grumbling About Limitations
- Some Thoughts on the Nature of What We Do
- Working with Predicates in Collections
- Working with DataReaders
- Outputting XML with XmlWriter
- Writing XML Data
- Working with Compression
- Another Look at Compressed Streams
- Compressing a Very Large File
- Canonical URIs
- Constructing URIs
- Using OneWayAttribute for Remote Calls
- Selecting a Garbage Collector
- Linked List
- Linked List Application - The MRU List
- Auto-implemented Properties in C#
- The HashSet Collection
- Looking Ahead: 2018
- An Experiment in Optimization
- A Larger Integer
- Extension Methods
- Language Integrated Query (LINQ)
- Variable Length Parameter Lists
- The ReaderWriterLockSlim Synchronization Primitive
- Sorting a Text File
- Sorting a Large Text File
- Using ListView with Large Data Sets
- LINQ One-Liners
- Regular Expression Optimization
- Random File I/O
- Computing the Size of a Structure
- More on Computing Structure Sizes
- UnmanagedMemoryStream
- Dynamically Loading Code
- Building a String Table
- Delegates Versus Function Pointers
- Visual Studio Editor Features
- A Simple Profile Timer
- New Features in C# 4.0
- IEnumerator or IList?
- New Features in .NET 4.0
- Set Operations with IEnumerable and HashSet
- Using File Locks
- Extending Object Functionality
- Clearing a HashSet
- When Hash Codes Matter
- Parsing Command Line Options
- Creating a Single-Instance Program
- Asynchronous Windows Forms Events
- The BackgroundWorker Component
- Fixing a Dumb Mistake
- Thinking About Multi-Threaded Programs
- JavaScript Object Notation
- Useful .NET-related Sites
- Markov Models
- Building an Order 0 Markov Model
- Higher Order Markov Models
- Webmaster's Guide to robots.txt
- An Overview of the Parallel Extensions to .NET
- Parallel Extensions Synchronization Objects
- Thread Safe Collections
- A Bug and a Conundrum
- Another Bug and an Answer
- Task Parallel Library
- Good and Bad Ideas in C#
- Parallel LINQ
- Copying Large Files
- Replacing File.Copy
- Learning from Our Mistakes
- Symbolic Links
- There Is No Easy Fix
- Tracking Hurricanes
- Examining Hurricane Data
- Searching for Multiple Strings
- Simple JSON Processing
- Aho-Corasick String Searching
- Writing a Web Crawler
- Web Crawler Politeness
- Source Control Management
- Subversion
- Communicating with Datagrams
- Fun with Actions and Funcs New
- The Future of Media
- The Importance of Metadata
- Of Comparison and IComparer
- IComparer, Comparer, IComparable, Oh My!
- Comparing Generic Types New
- A Simple HTTP Server New
- Informit Reference Library
Drawing Cycloid Curves
Last updated Sep 23, 2005.
One of my favorite childhood toys was the Spirograph. I spent hours experimenting with different wheels and colored pens, creating all manner of intricate designs.
The physical toy doesn't appear to be available anymore, except perhaps on the used market. I guess kids these days aren't interested in a toy if it doesn't have flashing lights and sound effects. That's too bad, really, but I'll refrain from the social commentary.
In its simplest form, the Spirograph toy consists of two plastic wheels that have interlocking teeth like gears. One of the gears is pinned to a drawing surface (usually a piece of paper placed on top of a piece of cardboard). The other gear has a number of holes in it that are large enough for a ballpoint pen tip. The user places the teeth of the floating gear into the teeth of the fixed gear, sticks the pen through one of the holes, and begins moving the floating gear around the fixed gear. The pen traces a path on the paper. The result is similar to Figure 47.
Figure 47: A design created by the Spirograph toy
Although it seemed magical to me as a child, there's really nothing magic about the Spirograph. It's just an example of a trochoid curve (a modified cycloid curve), something we can simulate on the computer fairly easily.
Simple Cycloid Curves
The simplest cycloid curve is drawn by tracing the path of a point at the edge of a circle as the circle rolls in a straight line. The MathWorld article linked above contains an animated Java applet that draws such a cycloid curve. I'll leave the animation for another time and focus first on drawing the curve.
The parametric equations for drawing a cycloid curve are given in the MathWorld article as:
x = a(t - sin t)
y = a(1 - cos t)
Where a is the radius of the circle and t is the rotation angle (in radians) of the point on the circle as it rolls along the line. These equations assume that the curve starts at the origin (position (0, 0)), so you have to add the actual starting coordinates to the computed values. Code below shows how to use these equations in drawing a cycloid curve.
[C#]
private void button1_Click(object sender, System.EventArgs e)
{
// Constants control the position and size of the circle
// and the number of points to plot on the curve.
const int baseLine = 200;
const Double radius = 40;
const int PointsPerCurve = 100;
Graphics g = CreateGraphics();
try
{
// Clear the drawing canvas
g.Clear(this.BackColor);
// Draw the base line
g.DrawLine(Pens.Black, 0, (float)baseLine, this.ClientRectangle.Right, (float)baseLine);
// Compute the starting point
PointF ptStart = new PointF((float)radius, (float)baseLine);
// Draw the curve
ptStart = DrawCycloid(g, ptStart, radius, PointsPerCurve);
// Draw it again starting at the previous end point
DrawCycloid(g, ptStart, radius, PointsPerCurve);
}
finally
{
g.Dispose();
}
}
PointF DrawCycloid(Graphics g, PointF ptStart, double radius, int PointsPerCurve)
{
// There are always 2*PI radians in a circle
const Double radiansPerCircle = 2 * Math.PI;
Double angleStep = radiansPerCircle / PointsPerCurve; // angle step, in radians
PointF oldPoint = ptStart;
Double angle = 0;
for (int pt = 0; pt < PointsPerCurve; pt++)
{
angle += angleStep;
// x = a(t-sin t)
// y = a(1-cos t)
// Point is traslated from the starting point.
PointF newPoint = new PointF(
ptStart.X + (float)(radius * (angle - Math.Sin(angle))),
ptStart.Y - (float)(radius * (1 - Math.Cos(angle))));
// Draw the curve segment
g.DrawLine(Pens.Red, oldPoint, newPoint);
// and setup for the next go 'round
oldPoint = newPoint;
}
// return the ending point
return oldPoint;
}
[Visual Basic]
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' Constants control the position and size of the circle
' and the number of points to plot on the curve.
Const baseLine As Integer = 200
Const radius As Double = 40
Const PointsPerCurve As Integer = 100
Dim g As Graphics = CreateGraphics()
Try
' Clear the drawing canvas
g.Clear(Me.BackColor)
' Draw the base line
g.DrawLine(Pens.Black, 0, baseLine, Me.ClientRectangle.Right, baseLine)
' Compute the starting point
Dim ptStart As New PointF(radius, baseLine)
' Draw the curve
ptStart = DrawCycloid(g, ptStart, radius, PointsPerCurve)
' Draw it again starting at the previous end point
DrawCycloid(g, ptStart, radius, PointsPerCurve)
Finally
g.Dispose()
End Try
End Sub
Private Function DrawCycloid(ByVal g As Graphics, ByVal ptStart As PointF, ByVal radius As Double, ByVal PointsPerCurve As Integer) As PointF
' There are always 2*PI radians in a circle
Const radiansPerCircle As Double = 2 * Math.PI
Dim angleStep As Double = radiansPerCircle / PointsPerCurve ' angle step, in radians
Dim oldPoint As PointF = ptStart
Dim angle As Double = 0
Dim pt As Integer
For pt = 1 To PointsPerCurve
angle = angle + angleStep
' x = a(t-sin t)
' y = a(1-cos t)
' Point is traslated from the starting point.
Dim newPoint As New PointF( _
ptStart.X + (radius * (angle - Math.Sin(angle))), _
ptStart.Y - (radius * (1 - Math.Cos(angle))))
'Draw the curve segment
g.DrawLine(Pens.Red, oldPoint, newPoint)
' and setup for the next go 'round
oldPoint = newPoint
Next
' return the ending point
Return oldPoint
End Function
This code is intended to be used in a Windows Forms application. The first method, <tt>button1_Click</tt>, sets up for drawing the curve. It allocates the <tt>Graphics</tt> object that will be drawn on, draws the base line, and then calls the <tt>DrawCycloid</tt> method to draw the actual cycloid curve.
The button click handler defines constants that determine the size of the circle and the number of line segments used to draw the curve. The number of line segments used determines the smoothness of the curve. More on that below.
The <tt>DrawCycloid</tt> method uses the parametric equations to compute the points on the curve and draw the line segments. It uses passed <tt>PointsPerCurve</tt> value to compute the angle step size. Figure 48 shows the curve as drawn by my sample program.
Figure 48 - The curve drawn by the example code
One thing you can do with the computer simulation that you can't easily do with a physical toy is adjust the number of line segments used to create the curve. The curve shown in Figure 48 was drawn by plotting 100 different points and drawing line segments between them. This results in a smooth curve for even much larger circles. Interesting things happen, though, if you drastically decrease the number of points on the curve. For example, if you change the <tt>PointsPerCurve<tt> value to 5, you end up with the "curve" shown in Figure 49.
Figure 49 - Decreasing the number of points on the curve
When you significantly reduce the number of line segments used to draw the curve, you can see the individual segments. The illusion of a smooth curve is destroyed. This doesn't look terribly exciting when drawing the curves on a straight line, but can create some interesting effects when you begin to draw the curves around a circle. We'll come back to that in a later section.



Account Sign In
View your cart