Spiro Designer


Anyone as old as I played with Spirograph at one time in their lives. For anyone not familiar, Spirograph was a design tool that allowed you to create intricate spiral patterns by rolling wheels around the inside of larger rings. A pen was stuck in a hole in the smaller wheel to draw.  By varying the size of the wheel and the location of the pen, very complex patterns could be produced.

Spiro designer is a partial implementation of Spirograph. Spiro Designer uses the Matrix and GraphicsPath classes with their Transform and Rotate methods to build a spiro. An example is shown below:

 

 

 

 



All the graphics work is done in the constructor for the Spiro object:

In this example we saw the use of Forms Authentication to identify a user and storing personalized settings for the identified users of the system. This logic can be extended to provide a user portal where the user can save his settings for stock quotes, weather, news etc. You can use this technique for personalization and expand on it to improve the mobile users experience at your site in ASP.Net Web Applications and Mobile Web Applications. Personalization gives the user a feeling of familiarity and also avoids repetitive data entry.  

public Spiro(SpiroPoint _center, int _radouter, int _radinner, int _offset,
int startangle, Color c, float width, int ndex)
{
center = _center;
pen = new SpiroPen(c, width);
radouter = _radouter;
radinner = _radinner;
offset = _offset;
angle = startangle;
index = ndex;
pts = new PointF[361];
types = new byte[361];
int radratio = radouter/radinner;
Point innercenterpoint = new Point(center.Point.X+radouter-radinner,center.Point.Y);
Point inneroffset = new Point(innercenterpoint.X+offset,center.Point.Y);
GraphicsPath gpOrigOuter = new GraphicsPath();
GraphicsPath gpOrigInner = new GraphicsPath();
gpOrigOuter.AddLine(center.Point,innercenterpoint);
gpOrigInner.AddLine(innercenterpoint, inneroffset);
Matrix outertrans = new Matrix(1, 0, 0, 1, 0, 0);
Matrix innertrans = new Matrix(1, 0, 0, 1, 0, 0);
GraphicsPath outer = new GraphicsPath(); outer = (GraphicsPath)gpOrigOuter.Clone();
GraphicsPath inner = new GraphicsPath();
inner = (GraphicsPath)gpOrigInner.Clone(); 
for(int n=0; n<361; n++)
{
outertrans.RotateAt(n, center.Point);
outer.Transform(outertrans);
Point newinneroffset = new Point((int)outer.GetLastPoint().X+offset,(int)outer.GetLastPoint().Y);
inner.AddLine(outer.GetLastPoint(),newinneroffset);
innertrans.RotateAt(n*(1-radratio), outer.GetLastPoint());
inner.Transform(innertrans);
pts[n] = inner.GetLastPoint();
types[n] = (byte)PathPointType.Line;
outertrans.Dispose();
outertrans = new Matrix(1, 0, 0, 1, 0, 0);
innertrans.Dispose();
innertrans = new Matrix(1, 0, 0, 1, 0, 0);
outer = (GraphicsPath)gpOrigOuter.Clone();
inner = (GraphicsPath)gpOrigInner.Clone();
}
gp = new GraphicsPath(pts, types);
if(startangle != 0)
{
Matrix finaltrans = new Matrix(1, 0, 0, 1, 0, 0);
finaltrans.RotateAt(startangle, center.Point);
gp.Transform(finaltrans);
}
}

Center is the center point of the outer ring, radouter is the radius of the outer ring, radinner is the radius of the inner wheel, offset is the distance from the center of the inner wheel the pen is fixed, startangle is the rotation of the spiro.

Two GraphicsPaths are initially created.  One is a line from the center of the outer ring to the center of the inner wheel.  The second is a line from the center of the inner wheel to the pen location.  After entering the loop, each of these is successively rotated the proper amount for each degree point on the circle.  The resultant point is saved in the pts[] array.  After all the points are generated, a final GraphicPath is created from the pts[] array.  Finally, the entire spiro is rotated if needed.  The picture below should help to visualize what is going on.

If you set the step values for the inputs, you can draw successive spiros by pressing the Draw Next button.  In the example above, the Angle step was set to 10 deg and the whole spiro was created with ten clicks of the mouse.  Highlighting a row in the Spiro Elements box will flash that spiro.  This is helpful to delete spiros after they are drawn because they is no other good way to tell which spiro is which.  A highlighted item can be deleted using the DEL key.  Every time a new color/width is used, a pen object is created and added to the Pen Selector box.  Selecting a pen in the Pen Selector box will make that the pen for the next spiro drawn.  Spiros can be saved as spiro files (*.sp) or as jpgs.  The path for the directory to save the files is hard coded to \Pictures off the current path.  You will need to change that if that location doesn't work for you. 

For simplicity, I used an ArrayList is used to store the spiros.  This is OK for less complex renderings, but with a lot of spiros, you will begin to see a noticeable redraw lag (generics - when?).  A good enhancement would be to use an array instead.

Setting parameters to get spiros to look the way you want can be tricky.  The model displays some behaviors that don't appear correct.  Many times you will get unexpected results - it takes a little practice to understand how to set the relative values.   I've included some .sp files you can load to get started.