Click here to Skip to main content
15,896,912 members
Articles / Mobile Apps

Symmetry Drawing Tool

Rate me:
Please Sign up or sign in to vote.
4.11/5 (30 votes)
31 May 2004CPOL3 min read 84.2K   1.7K   46  
An article describing the development and use of the Symmetry Drawing Tool.
  • symmetrydraw.zip
    • SymmetricDraw
      • App.ico
      • AssemblyInfo.cs
      • bin
        • Release
          • SymmetricDraw.exe
          • SymmetricDrawCE.exe
      • Bitmaps
        • Axes.bmp
        • Clear.bmp
        • Color.bmp
        • ColorSel.bmp
        • Filled.bmp
        • happy.bmp
        • Mirror.bmp
        • Open.bmp
        • Save.bmp
        • shape.bmp
        • Stamp.bmp
      • BitmapSaver.cs
      • cab
        • Release
          • CabWiz.PPC.log
          • CabWiz.WCE4.log
          • SymmetricDrawCE_PPC.ARM.CAB
          • SymmetricDrawCE_PPC.ARM.DAT
          • SymmetricDrawCE_PPC.ARMV4.CAB
          • SymmetricDrawCE_PPC.ARMV4.DAT
          • SymmetricDrawCE_PPC.MIPS.CAB
          • SymmetricDrawCE_PPC.MIPS.DAT
          • SymmetricDrawCE_PPC.SH3.CAB
          • SymmetricDrawCE_PPC.SH3.DAT
          • SymmetricDrawCE_PPC.WCE420X86.CAB
          • SymmetricDrawCE_PPC.WCE420X86.DAT
          • SymmetricDrawCE_PPC.X86.CAB
          • SymmetricDrawCE_PPC.X86.DAT
          • SymmetricDrawCE_WCE4.ARMV4.CAB
          • SymmetricDrawCE_WCE4.ARMV4.DAT
          • SymmetricDrawCE_WCE4.ARMV4T.CAB
          • SymmetricDrawCE_WCE4.ARMV4T.DAT
          • SymmetricDrawCE_WCE4.MIPS16.CAB
          • SymmetricDrawCE_WCE4.MIPS16.DAT
          • SymmetricDrawCE_WCE4.MIPSII.CAB
          • SymmetricDrawCE_WCE4.MIPSII.DAT
          • SymmetricDrawCE_WCE4.MIPSII_FP.CAB
          • SymmetricDrawCE_WCE4.MIPSII_FP.DAT
          • SymmetricDrawCE_WCE4.MIPSIV.CAB
          • SymmetricDrawCE_WCE4.MIPSIV.DAT
          • SymmetricDrawCE_WCE4.MIPSIV_FP.CAB
          • SymmetricDrawCE_WCE4.MIPSIV_FP.DAT
          • SymmetricDrawCE_WCE4.SH3.CAB
          • SymmetricDrawCE_WCE4.SH3.DAT
          • SymmetricDrawCE_WCE4.SH4.CAB
          • SymmetricDrawCE_WCE4.SH4.DAT
          • SymmetricDrawCE_WCE4.X86.CAB
          • SymmetricDrawCE_WCE4.X86.DAT
      • ColorCE.cs
      • ColorCE.resx
      • curve.cs
      • frmSym.cs
      • frmSym.resx
      • frmSymCE.cs
      • frmSymCE.resx
      • SymmetricDraw.csproj
      • SymmetricDraw.csproj.user
      • SymmetricDrawCE.csdproj
      • SymmetricDrawCE.csdproj.user
      • SymmetryTool.cs
    • Symmetry.sln
    • SymmetryCE.sln
using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

/// SymmetricDrw
/// 
/// Written by Doug Mair
/// Copyright (c) 2004 - All rights reserved.
/// 

namespace SymmetricDraw
{
	public class MyPoint
	{
		public double m_centerX, m_centerY;
		public double m_angle, m_rad;
		private double m_x, m_y;

		public MyPoint()
		{
			x = 0;
			y = 0;
		}

		public MyPoint(double nx, double ny)
		{
			x = nx;
			y = ny;
		}

		public MyPoint rotated(double theta) 
		{
			double c, s;
			double nx, ny;

			nx = x - m_centerX;
			ny = y - m_centerY;

			c = Math.Cos(theta);
			s = Math.Sin(theta);
			MyPoint Q = new MyPoint(c*nx - s*ny, s*nx + c*ny);
			Q.x = Q.x + m_centerX;
			Q.y = Q.y + m_centerY;
			return(Q);
		}

		public void CalcRad()
		{
			double	dx, dy;

			dx = x - m_centerX;
			dy = y - m_centerY;
			m_rad = Math.Sqrt(dx * dx + dy * dy);
			if (m_rad != 0)
				m_angle = -Math.Acos(dx / m_rad);
			else
				m_angle = 0;

			if (m_y > m_centerY)
				m_angle = -m_angle;
		}

		public void SetCenter(ref MyPoint p)
		{
			m_centerX = p.x;
			m_centerY = p.y;
			CalcRad();
		}

		public void SetPos(double nx, double ny)
		{
			x = nx;
			y = ny;
			CalcRad();
		}

		public void SetRel(double dx, double dy)
		{
			x += dx;
			y += dy;
			CalcRad();
		}

		public double x 
		{
			get { return m_x; }
			set { m_x = value; }
		}

		public double y
		{
			get { return m_y; }
			set { m_y = value; }
		}

		public int IX 
		{
			get { return Convert.ToInt32(m_x); }
		}

		public int IY
		{
			get { return Convert.ToInt32(m_y); }
		}

		public int XR(double deltaAngle)
		{
			return Convert.ToInt32(m_centerX + m_rad * Math.Cos(m_angle + deltaAngle));
		}

		public int YR(double deltaAngle)
		{
			return Convert.ToInt32(m_centerY + m_rad * Math.Sin(m_angle + deltaAngle));
		}

		public int XRm(double dm, double deltaAngle)
		{
			return Convert.ToInt32(m_centerX + m_rad * Math.Cos(dm-m_angle + deltaAngle));
		}

		public int YRm(double dm, double deltaAngle)
		{
			return Convert.ToInt32(m_centerY + m_rad * Math.Sin(dm-m_angle + deltaAngle));
		}

		public bool PntInBnd(int nx, int ny, int nWidth)
		{
			if ((Math.Abs(nx-x) <= nWidth) && (Math.Abs(ny-y) <= nWidth))
				return true;
			else
				return false;
		}
	}

	/// <summary>
	/// Summary description for SymmetryTool.
	/// </summary>
	public class SymmetryTool
	{
		public MyPoint[] p;

		public const int PCenter = 0;
		public const int PAxis = 1;
		public const int PMid = 2;
		public const int PRot = 3;
		public const int PData = 4;
		public const int PNone = -1;

		public const int nPnts = 12;
		public const int nGuideWidth = 4;
		public Image drawImage;
		public bool bImage;
		public bool TextShape;

		private double rotAngle = 0;
		private double rotRadius = 20;

		public SymmetryTool()
		{
			p = new MyPoint[PData + nPnts];

			for (int i=0; i<nPnts; i++)
				p[i] = new MyPoint();

			cColor = System.Drawing.Color.Black;
			bImage = false;
		}

		public int ClickOn(int x, int y)
		{
			for (int i=0; i<nPnts; i++)
				if (p[i].PntInBnd(x,y, nGuideWidth))
                    return i;
			return PNone;
		}

		public void SetCenter(double nx, double ny)
		{
			p[PCenter].SetPos(nx, ny);
		}

		private Color cColor;
		public Color ShapeColor
		{
			get { return cColor; }
			set { cColor = value; }
		}

		private int nAxes;
		public int Axes 
		{
			get { return nAxes; }
			set { nAxes = value; }
		}

		private int nMaxDataPnts;
		public int MaxDataPnts
		{
			get { return nMaxDataPnts; }
			set { nMaxDataPnts = value; }
		}

		private int nDataPnts;
		public int DataPnts
		{
			get { return nDataPnts; }
			set { nDataPnts = value; }
		}

		private bool bMirror;
		public bool Mirror
		{
			get { return bMirror; }
			set { bMirror = value; }
		}

		private bool bText;
		public bool Text
		{
			get { return bText; }
			set { bText = value; }
		}

		private bool bCurve;
		public bool Curve
		{
			get { return bCurve; }
			set 
			{ 
				/*
				int x1, y1, x2, y2;

				x1 = p[PData+0].IX;	y1 = p[PData+0].IY;
				x2 = p[PData+1].IX;	y2 = p[PData+1].IY;

				if (value)
				{
					p[PData+2].SetPos((x1+x2)/2, (y1+y2)/2);
					p[PData+3].SetPos((x1+x2)/2, (y1+y2)/2);
				}
				*/
				bCurve = value; 
			}
		}

		private bool bFilled;
		public bool Filled
		{
			get { return bFilled; }
			set { bFilled = value; }
		}

		public void SetPos(int pt, int nx, int ny, bool bRel)
		{
			double	dx, dy;
			int		i;

			i = (int)pt;
			dx = p[i].x - (double)nx;
			dy = p[i].y - (double)ny;

			if (i == PAxis)
			{
				double a1, a2;
				MyPoint pNew = new MyPoint();

				a1 = p[PAxis].m_angle;
				p[PAxis].SetPos((double)nx, (double)ny);
				a2 = p[PAxis].m_angle;

				for (i=0; i<MaxDataPnts; i++)
				{
					pNew = p[PData+i].rotated(a2-a1);
					p[PData+i].SetPos(pNew.x, pNew.y);
				}
			}
			else if (i == PRot)
			{
				double oldAngle;
				MyPoint pNew = new MyPoint();

				oldAngle = rotAngle;
				p[PRot].SetCenter(ref p[PMid]);
				p[PRot].SetPos((double)nx, (double)ny);
				rotAngle = p[PRot].m_angle;
				rotRadius = p[PRot].m_rad;

				for (i=0; i<MaxDataPnts; i++)
				{
					p[PData+i].SetCenter(ref p[PMid]);
					pNew = p[PData+i].rotated(rotAngle-oldAngle);
					p[PData+i].SetPos(pNew.x, pNew.y);
				}
			}
			else if (i == PCenter)
			{
				for (i=0; i<nPnts; i++)
					p[i].SetRel(-dx, -dy);
			}
			else
			{
				if ((bRel && (i>=PData)) || (i==PMid))
				{
					for (i=0; i<MaxDataPnts; i++)
						p[PData+i].SetRel(-dx, -dy);
				} 
				else
					p[i].SetPos((double)nx, (double)ny);
			}
		}

		public void DrawGuides(Graphics drawingSurface)
		{
			int i;
			double xt, yt;
			double deltaAngle, angleSection;
			Pen pen1 = new Pen(Color.Red);
			Pen pen2 = new Pen(Color.Gray);

			xt = 0;
			yt = 0;
			for (i=0; i<MaxDataPnts; i++)
			{
				drawingSurface.DrawEllipse(pen1, p[PData+i].IX-nGuideWidth, p[PData+i].IY-nGuideWidth, nGuideWidth*2, nGuideWidth*2);
				xt += p[PData+i].x;
				yt += p[PData+i].y;
			}
			p[PMid].x = xt / MaxDataPnts;
			p[PMid].y = yt / MaxDataPnts;
			p[PRot].x = p[PMid].x + rotRadius * Math.Cos(rotAngle);
			p[PRot].y = p[PMid].y + rotRadius * Math.Sin(rotAngle);

			drawingSurface.DrawRectangle(pen1, p[PMid].IX-nGuideWidth, p[PMid].IY-nGuideWidth, nGuideWidth*2, nGuideWidth*2);
			drawingSurface.DrawEllipse(pen1, p[PRot].IX-nGuideWidth, p[PRot].IY-nGuideWidth, nGuideWidth*2, nGuideWidth*2);
			drawingSurface.DrawLine(pen2, p[PMid].IX, p[PMid].IY, p[PRot].IX, p[PRot].IY);

			for (i=1; i<MaxDataPnts; i++)
				drawingSurface.DrawLine(pen2, p[PData+i].IX, p[PData+i].IY, p[PData+i-1].IX, p[PData+i-1].IY);

			drawingSurface.DrawRectangle(pen2, p[PCenter].IX-nGuideWidth, p[PCenter].IY-nGuideWidth, nGuideWidth*2, nGuideWidth*2);
			drawingSurface.DrawEllipse(pen2, p[PAxis].IX-nGuideWidth, p[PAxis].IY-nGuideWidth, nGuideWidth*2, nGuideWidth*2);

			p[PAxis].SetCenter(ref p[PCenter]);
			deltaAngle = Math.PI * 2 / (double)nAxes;
			for (i=0; i<nAxes; i++)
			{
				angleSection = deltaAngle * i;
				drawingSurface.DrawLine(pen2, p[PAxis].XR(angleSection), p[PAxis].YR(angleSection), p[PCenter].IX, p[PCenter].IY);
			}
		}

		public double CalcRad(double w, double h)
		{
			return Math.Sqrt(w*w + h*h);
		}

		public float CalcAng(ref Point p1, ref Point p2, ref double nRad)
		{
			double	dx, dy, nNewAngle;

			dx = p2.X - p1.X;
			dy = p2.Y - p1.Y;
			nRad = CalcRad(dx, dy);
			if (nRad != 0)
				nNewAngle = -Math.Acos(dx / nRad);
			else
				nNewAngle = 0;

			if (p1.Y > p2.Y)
				nNewAngle = -nNewAngle;
			return (float)((-nNewAngle - Math.PI/4) * 180 / Math.PI);
		}

		public void DrawSymShapes(Graphics drawingSurface)
		{
			int		i, j;
			double	angleAxis, deltaAngle, angleSection;
#if (WINCE)
			Pen pen = new Pen(ShapeColor);
#else
			Pen pen = new Pen(ShapeColor, 2);
#endif
			for (i=0; i<MaxDataPnts; i++)
				p[PData+i].SetCenter(ref p[PCenter]);

			deltaAngle = Math.PI * 2 / (double)nAxes;

			Rectangle destRect = new Rectangle(0, 0, 1, 1);
			double nImageRad = 0;

			if (bImage || bText)
			{
				nImageRad = CalcRad(drawImage.Width, drawImage.Height);
				destRect = new Rectangle(0, 0, drawImage.Width, drawImage.Height);
			}
					
			angleAxis = 2 * p[PAxis].m_angle;
			for (i=0; i<nAxes; i++)
			{
				double nLineRad = 0;
				SolidBrush brush = new SolidBrush(ShapeColor);
				angleSection = deltaAngle * i;

				Point[] cPnts = new Point[MaxDataPnts];
				for (j=0; j<MaxDataPnts; j++)
					cPnts[j] = new Point(p[PData+j].XR(angleSection), p[PData+j].YR(angleSection));

				if (bImage || bText)
				{
					ImageAttributes imageAttr = new ImageAttributes();
					float angleLine = CalcAng(ref cPnts[0], ref cPnts[1], ref nLineRad);
					destRect.Width = Convert.ToInt32(drawImage.Width * nLineRad / nImageRad);
					destRect.Height = Convert.ToInt32(drawImage.Height * nLineRad / nImageRad);
					Color lowerColor = Color.FromArgb(255, 0, 255);
					Color upperColor = Color.FromArgb(255, 0, 255);
					imageAttr.SetColorKey(lowerColor, upperColor); //, ColorAdjustType.Default);
#if (WINCE)
					destRect.Height *= 2;
					destRect.Width *= 2;
					destRect.X = Convert.ToInt32(cPnts[0].X-destRect.Width/2);
					destRect.Y = Convert.ToInt32(cPnts[0].Y-destRect.Height/2);
					drawingSurface.DrawImage(drawImage, destRect, 0, 0, drawImage.Width, drawImage.Height, GraphicsUnit.Pixel, imageAttr);
#else
					drawingSurface.TranslateTransform(cPnts[0].X, cPnts[0].Y);
					drawingSurface.RotateTransform(angleLine);
					drawingSurface.DrawImage(drawImage, destRect, 0, 0, drawImage.Width, drawImage.Height, GraphicsUnit.Pixel,imageAttr);
					drawingSurface.ResetTransform();
#endif
				}
				else if ((MaxDataPnts > 2) && (bCurve || bFilled))
				{
#if (WINCE)
					Point[] ps = new Point[0];
					curve.addCurve(ref ps, cPnts[0], cPnts[1], cPnts[2], cPnts[3]);
					if ((MaxDataPnts > 4) && (DataPnts > 4))
						curve.addCurve(ref ps, cPnts[3], cPnts[4], cPnts[5], cPnts[6]);
					curve.draw(ref drawingSurface, ref pen, ref brush, ref ps, bFilled);
#else
					GraphicsPath gp = new GraphicsPath();
					gp.AddBezier(cPnts[0], cPnts[1], cPnts[2], cPnts[3]);
					if (MaxDataPnts > 4)
						gp.AddBezier(cPnts[3], cPnts[4], cPnts[5], cPnts[6]);
					if (bFilled)
						drawingSurface.FillPath(brush, gp);
					else
						drawingSurface.DrawPath(pen, gp);
#endif
					if (bMirror)
					{
						for (j=0; j<MaxDataPnts; j++)
							cPnts[j] = new Point(p[PData+j].XRm(angleAxis, angleSection), p[PData+j].YRm(angleAxis, angleSection));
#if (WINCE)
						ps = new Point[0];
						curve.addCurve(ref ps, cPnts[0], cPnts[1], cPnts[2], cPnts[3]);
						if ((MaxDataPnts > 4) && (DataPnts > 4))
							curve.addCurve(ref ps, cPnts[3], cPnts[4], cPnts[5], cPnts[6]);
						curve.draw(ref drawingSurface, ref pen, ref brush, ref ps, bFilled);
#else
						gp = new GraphicsPath();
						gp.AddBezier(cPnts[0], cPnts[1], cPnts[2], cPnts[3]);
						if (MaxDataPnts > 4)
							gp.AddBezier(cPnts[3], cPnts[4], cPnts[5], cPnts[6]);
						if (bFilled)
							drawingSurface.FillPath(brush, gp);
						else
							drawingSurface.DrawPath(pen, gp);
#endif
					}
				}
				else
				{
					drawingSurface.DrawLine(pen, 
						p[PData+0].XR(angleSection), p[PData+0].YR(angleSection), 
						p[PData+1].XR(angleSection), p[PData+1].YR(angleSection));

					if (bMirror)
					{
						drawingSurface.DrawLine(pen, 
							p[PData+0].XRm(angleAxis, angleSection), p[PData+0].YRm(angleAxis, angleSection),
							p[PData+1].XRm(angleAxis, angleSection), p[PData+1].YRm(angleAxis, angleSection)); 
					}
				}
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Corpria LLC
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions