简单写了个效果 如图 lib文件using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Drawing.Drawing2D;namespace yangzhanglib { public class DrawString { /// <summary> /// 根据角度 获取椭圆上一点的坐标 /// x2⒈/a2+y2/b2=1 /// y = x * tanα /// </summary> /// <param name="a">长半轴</param> /// <param name="b">短半轴</param> /// <param name="rotate">角度</param> /// <returns></returns> public static Point GetCoordinate(int a, int b, float rotate) { double x = 0, y = 0, tan = 0, Rad = 0;
if (Math.Abs(rotate) > 90) Rad = (Math.Abs(rotate) - 90); else Rad = (90 - Math.Abs(rotate)); Rad = Rad * 2 * Math.PI / 360; tan = Math.Tan(Rad); x = Math.Sqrt((double)1 / ((double)1 / (a * a) + (tan * tan) / (b * b))); y = x * tan; if (rotate < 0) x = 0 - x; if (rotate > -90 && rotate < 90) y = 0 - y; x = a + x; y = b + y; return new Point((int)Math.Round(x), (int)Math.Round(y)); } public static Bitmap DrawText(string text) { char[] texts = text.ToArray(); int beginRotate = -120; int endRotate = 120; float Rotate = (float)(endRotate - beginRotate) / (texts.Length - 1); int ecllpse_width = 200; int ecllpse_height = 150; int fontsize = 18; Bitmap map = new Bitmap(ecllpse_width *2, ecllpse_height *2); using (Graphics g = Graphics.FromImage(map)) { g.FillRectangle(new SolidBrush(Color.White),new Rectangle(0,0,(int)ecllpse_width *2, (int)ecllpse_height *2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot}, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle((2 * ecllpse_width / 10), (2 * ecllpse_height / 10), (8 * ecllpse_width / 10) * 2, (8 * ecllpse_height / 10) * 2)); for (int i = 0; i < texts.Length; i++) { Matrix mtxSave = g.Transform; float now_rotate = beginRotate + (Rotate * i); Point p = GetCoordinate(13 * ecllpse_width / 20, 13 * ecllpse_height / 20, beginRotate + (Rotate * i)); Matrix mtxRotate = g.Transform; p.X += ecllpse_width / 4; p.Y += ecllpse_height / 4; mtxRotate.RotateAt(beginRotate + (Rotate * i), new PointF(p.X + fontsize, p.Y + fontsize)); g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave; } } return map; }
} } 页面cs代码using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using yangzhanglib;namespace yangzhang { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Response.Clear(); Response.CacheControl = "no-cache"; Response.ContentType = "image/jpeg"; using (System.Drawing.Bitmap map = DrawString.DrawText("北京开天科技有限公司样品章")) { byte[] bytes; using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { System.Drawing.Imaging.ImageCodecInfo[] icis = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); System.Drawing.Imaging.ImageCodecInfo ici = null; foreach (System.Drawing.Imaging.ImageCodecInfo i in icis) { if (i.MimeType == "image/jpeg") { ici = i; } } System.Drawing.Imaging.EncoderParameters ep = new System.Drawing.Imaging.EncoderParameters(1); ep.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)90); map.Save(ms, ici, ep); bytes = ms.ToArray(); ms.Close(); ms.Dispose(); } Response.OutputStream.Write(bytes, 0, bytes.Length); }
lib 做了调整,画图的思路 使用椭圆内 等边多边形的思路来做。效果图 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Drawing.Drawing2D;namespace yangzhanglib { public class DrawString { /// <summary> /// 根据角度 获取椭圆上一点的坐标 /// x2⒈/a2+y2/b2=1 /// y = x * tanα /// </summary> /// <param name="a">长半轴</param> /// <param name="b">短半轴</param> /// <param name="rotate">角度</param> /// <returns></returns> public static Point GetCoordinate(int a, int b, float rotate) { double x = 0, y = 0, tan = 0, Rad = 0;
if (Math.Abs(rotate) > 90) Rad = (Math.Abs(rotate) - 90); else Rad = (90 - Math.Abs(rotate)); Rad = Rad * 2 * Math.PI / 360; tan = Math.Tan(Rad); x = Math.Sqrt((double)1 / ((double)1 / (a * a) + (tan * tan) / (b * b))); y = x * tan; if (rotate < 0) x = 0 - x; if (rotate > -90 && rotate < 90) y = 0 - y; x = a + x; y = b + y; return new Point((int)Math.Round(x), (int)Math.Round(y)); } public static Bitmap DrawText(string text) { char[] texts = text.ToArray(); int beginRotate = -120; int endRotate = 120; float Rotate = (float)(endRotate - beginRotate) / (texts.Length - 1); int ecllpse_width = 200; int ecllpse_height = 150; int fontsize = 18; Bitmap map = new Bitmap(ecllpse_width *2, ecllpse_height *2); using (Graphics g = Graphics.FromImage(map)) { g.FillRectangle(new SolidBrush(Color.White),new Rectangle(0,0,(int)ecllpse_width *2, (int)ecllpse_height *2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot}, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle((2 * ecllpse_width / 10), (2 * ecllpse_height / 10), (8 * ecllpse_width / 10) * 2, (8 * ecllpse_height / 10) * 2)); for (int i = 0; i < texts.Length; i++) { Matrix mtxSave = g.Transform; float now_rotate = beginRotate + (Rotate * i); Point p = GetCoordinate(13 * ecllpse_width / 20, 13 * ecllpse_height / 20, beginRotate + (Rotate * i)); Matrix mtxRotate = g.Transform; p.X += ecllpse_width / 4; p.Y += ecllpse_height / 4; mtxRotate.RotateAt(beginRotate + (Rotate * i), new PointF(p.X + fontsize, p.Y + fontsize));
g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave; } } return map; } public struct Coordinate { public int x; public int y; } /// <summary> /// 获取角度 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static double GetRotate(double x, double y) { if(x < 0 && y < 0) return -270 - Math.Atan2(y, x) * 180 / Math.PI; else return 90 - Math.Atan2(y, x) * 180 / Math.PI; } /// <summary> /// 一元1次方程求解 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <param name="d"></param> /// <param name="e"></param> /// <returns></returns> public static double m1(double a, double b) { return (-1 * b) / a; } /// <summary> /// 一元2次方程求解 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <param name="d"></param> /// <param name="e"></param> /// <returns></returns> public static double[] m2(double a, double b, double c) { if (a == 0) return new double[] { m1(b, c) }; if (c == 0) return new double[] { m1(a, b), 0 }; double Discriminant = b * b - 4 * a * c; return new double[]{ (-1 * b + Math.Sqrt(Discriminant)) / (2 * a) ,(-1 * b - Math.Sqrt(Discriminant)) / ( 2 * a) }; } /// <summary> /// 盛金公式法 一元3次方程求解 /// 当A=B=0时,方程有一个三重实根。 /// 当Δ=B^2-4AC>0时,方程有一个实根和一对共轭虚根。 /// 当Δ=B^2-4AC=0时,方程有三个实根,其中有一个二重根。 /// 当Δ=B^2-4AC<0时,方程有三个不相等的实根。 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <param name="d"></param> /// <param name="e"></param> /// <returns></returns> public static double[] m3(double a, double b, double c, double d) { if (a == 0) return m2(b, c, d); if (d == 0) return m2(a, b, c).Concat(new double[] { 0 }).ToArray(); //重根判别式 double A = b * b - 3 * a * c; double B = b * c - 9 * a * d; double C = c * c - 3 * b * d; //总判别式 double Discriminant = B * B - 4 * A * C; if (A == 0 && B == 0) return new double[] { -1 * b / 3 * a }; if (Discriminant > 0) { double Y1 = A * b + 3 * a * (-1 * B + Math.Sqrt(Discriminant)) / 2; double Y2 = A * b + 3 * a * (-1 * B - Math.Sqrt(Discriminant)) / 2; return new double[] { -1 * b - (Math.Pow(Y1, 1.0 / 3.0) + Math.Pow(Y2, 1.0 / 3.0)) / 3 * a }; } if (Discriminant == 0) { double K = B / A; return new double[] { (-1 * b / a) + K, -1 * K / 2 }; } if (Discriminant < 0) { double T = (2 * A * b - 3 * a * B) / (a * Math.Sqrt(Math.Pow(A, 3))); double O = Math.Acos(T); return new double[] { (-1 * b - 2 * Math.Sqrt(A) * Math.Cos(O/3))/(3*a), (-1 * b + Math.Sqrt(A) * (Math.Cos(O/3) + Math.Sqrt(3) * Math.Sin(O/3)))/(3*a), (-1 * b + Math.Sqrt(A) * (Math.Cos(O/3) - Math.Sqrt(3) * Math.Sin(O/3)))/(3*a) }; } return new double[] { }; }
/// <summary> /// 费拉里法 一元4次方程求解 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <param name="d"></param> /// <param name="e"></param> /// <returns></returns> public static double[] m4(double a, double b, double c, double d, double e) { if (a == 0) return m3(b, c, d, e); if (e == 0) return m3(a, b, c, d).Concat(new double[] { 0 }).ToArray(); if (a != 1) { b /= a; c /= a; d /= a; e /= a; } // Coefficients for cubic solver double cb, cc, cd; double discrim, q, r, RRe, RIm, DRe, DIm, dum1, ERe, EIm, s, t, term1, r13, sqR, y1, z1Re, z1Im, z2Re; cb = -c; cc = -4.0 * e + d * b; cd = -(b * b * e + d * d) + 4.0 * c * e; q = (3.0 * cc - (cb * cb)) / 9.0; r = -(27.0 * cd) + cb * (9.0 * cc - 2.0 * (cb * cb)); r /= 54.0; discrim = q * q * q + r * r; term1 = (cb / 3.0); if (discrim > 0) { // 1 root real, 2 are complex s = r + Math.Sqrt(discrim); s = ((s < 0) ? -Math.Pow(-s, (1.0 / 3.0)) : Math.Pow(s, (1.0 / 3.0))); t = r - Math.Sqrt(discrim); t = ((t < 0) ? -Math.Pow(-t, (1.0 / 3.0)) : Math.Pow(t, (1.0 / 3.0))); y1 = -term1 + s + t; } else { if (discrim == 0) { r13 = ((r < 0) ? -Math.Pow(-r, (1.0 / 3.0)) : Math.Pow(r, (1.0 / 3.0))); y1 = -term1 + 2.0 * r13; } else { q = -q; dum1 = q * q * q; dum1 = Math.Acos(r / Math.Sqrt(dum1)); r13 = 2.0 * Math.Sqrt(q); y1 = -term1 + r13 * Math.Cos(dum1 / 3.0); } } // Determined y1, a real root of the resolvent cubic. term1 = b / 4.0; sqR = -c + term1 * b + y1; RRe = RIm = DRe = DIm = ERe = EIm = z1Re = z1Im = z2Re = 0; if (sqR >= 0) { if (sqR == 0) { dum1 = -(4.0 * e) + y1 * y1; if (dum1 < 0) //D and E will be complex z1Im = 2.0 * Math.Sqrt(-dum1); else { //else (dum1 >= 0) z1Re = 2.0 * Math.Sqrt(dum1); z2Re = -z1Re; } } else { RRe = Math.Sqrt(sqR); z1Re = -(8.0 * d + b * b * b) / 4.0 + b * c; z1Re /= RRe; z2Re = -z1Re; } } else { RIm = Math.Sqrt(-sqR); z1Im = -(8.0 * d + b * b * b) / 4.0 + b * c; z1Im /= RIm; z1Im = -z1Im; } z1Re += -(2.0 * c + sqR) + 3.0 * b * term1; z2Re += -(2.0 * c + sqR) + 3.0 * b * term1; //At this point, z1 and z2 should be the terms under the square root for D and E if (z1Im == 0) { // Both z1 and z2 real if (z1Re >= 0) { DRe = Math.Sqrt(z1Re); } else { DIm = Math.Sqrt(-z1Re); } if (z2Re >= 0) { ERe = Math.Sqrt(z2Re); } else { EIm = Math.Sqrt(-z2Re); } } else { r = Math.Sqrt(z1Re * z1Re + z1Im * z1Im); r = Math.Sqrt(r); dum1 = Math.Atan2(z1Im, z1Re); dum1 /= 2; //Divide this angle by 2 ERe = DRe = r * Math.Cos(dum1); DIm = r * Math.Sin(dum1); EIm = -DIm; } return new double[] { -term1 + (RRe + DRe) / 2 + (RIm + DIm) / 2 , -(term1 + DRe / 2) + RRe / 2 + (-DIm + RIm) / 2, -(term1 + RRe / 2) + ERe / 2 + (-RIm + EIm) / 2, -(term1 + (RRe + ERe) / 2) - (RIm + EIm) / 2 }; } public static Coordinate[] GetIntersection(double polygonWidth, double x, double y, double width, double height) { List<Coordinate> list = new List<Coordinate>(); double a, b, c, d, e, tan, A, B, C; tan = GetRotate(x, y); A = 1 - (double)Math.Pow(width, 2) / Math.Pow(height, 2); B = -2 * y; C = Math.Pow(x, 2) + Math.Pow(y, 2) - Math.Pow(polygonWidth, 2) + Math.Pow(width, 2); a = Math.Pow(A, 2); b = 2 * A * B; c = 2 * A * C + Math.Pow(B, 2) + 4 * Math.Pow(x, 2) * Math.Pow(width, 2) / Math.Pow(height, 2); d = 2 * B * C; e = Math.Pow(C, 2) - 4 * Math.Pow(x, 2) * Math.Pow(width, 2); double[] array = m4(a, b, c, d, e); for (int i = 0; i < array.Length; i++) { double y1 = array[i]; if (Math.Abs(y1) > height) continue; double x1 = width * Math.Sqrt(1 - Math.Pow(y1, 2) / Math.Pow(height, 2)); list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) }); x1 = -1 * x1; list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) }); } return list.ToArray(); ; } /// <summary> /// 根据椭圆上的一点,求出它顺时针另外的一个点,使这2个点的距离等于一个定值 /// </summary> /// <param name="polygonWidth"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="width"></param> /// <param name="height"></param> /// <returns></returns> public static Coordinate GetNextCoordinate(double polygonWidth, double x, double y, double width, double height) { double tan = GetRotate(x, y); Coordinate[] array = GetIntersection(polygonWidth, x, y, width, height);
for (int i = 0; i < array.Length; i++) { double y1 = array[i].y ; double x1 = array[i].x; if (GetRotate(x1 , y1) >= tan) return new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) }; } return new Coordinate() { x = 0, y = 0 }; } /// <summary> /// 根据椭圆上的一点,求出它逆时针另外的一个点,使这2个点的距离等于一个定值 /// </summary> /// <param name="polygonWidth"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="width"></param> /// <param name="height"></param> /// <returns></returns> public static Coordinate GetPrevCoordinate(double polygonWidth, double x, double y, double width, double height) { double tan = GetRotate(x, y); Coordinate[] array = GetIntersection(polygonWidth, x, y, width, height); for (int i = 0; i < array.Length; i++) { double y1 = array[i].y; double x1 = array[i].x; if (GetRotate(x1, y1) <= tan) return new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) }; } return new Coordinate() { x = 0, y = 0 }; } /// <summary> /// 根据字数的个数,获取指定椭圆内的 等边多边形 各个顶点的直角坐标系的坐标,以数组形式返回 /// </summary> /// <param name="polygonWidth"></param> /// <param name="textLength"></param> /// <param name="width"></param> /// <param name="height"></param> /// <returns></returns> public static Coordinate[] GetCoordinateArray(int polygonWidth, int textLength, int width, int height) { Coordinate[] result = new Coordinate[textLength]; if (textLength % 2 == 0) { //偶数个字符 int x = polygonWidth / 2; int y = (int)Math.Sqrt(height * height * (1 - (x * x) / (width * width))); result[textLength / 2] = new Coordinate() { x = -1 * x, y = y }; result[(textLength / 2) - 1] = new Coordinate() { x = x, y = y }; for (int i = (textLength / 2) - 2; i >= 0; i--) { result[i] = GetPrevCoordinate(polygonWidth, result[i + 1].x, result[i + 1].y, width, height); } for (int i = (textLength / 2) + 1; i < textLength; i++) { result[i] = GetNextCoordinate(polygonWidth, result[i - 1].x, result[i - 1].y, width, height); } } else { //奇数个字符 result[(textLength - 1) / 2] = new Coordinate() { x = 0, y = height }; for (int i = (textLength - 1) / 2 - 1; i >= 0; i--) { result[i] = GetPrevCoordinate(polygonWidth, result[i + 1].x, result[i + 1].y, width, height); } for (int i = (textLength - 1) / 2 + 1; i < textLength; i++) { result[i] = GetNextCoordinate(polygonWidth, result[i - 1].x, result[i - 1].y, width, height); } } return result; }
public static Bitmap DrawText2(string text) { int PolygonWidth = 43; int ecllpse_width = 200; int ecllpse_height = 150; int fontsize = 18; char[] texts = text.ToArray(); Coordinate[] arrayCoordinate = GetCoordinateArray(PolygonWidth, texts.Length, ecllpse_width * 65 / 100, ecllpse_height * 65 / 100); Bitmap map = new Bitmap(ecllpse_width * 2, ecllpse_height * 2); using (Graphics g = Graphics.FromImage(map)) { g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, (int)ecllpse_width * 2, (int)ecllpse_height * 2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot }, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle((2 * ecllpse_width / 10), (2 * ecllpse_height / 10), (8 * ecllpse_width / 10) * 2, (8 * ecllpse_height / 10) * 2)); for (int i = 0; i < texts.Length; i++) { Matrix mtxSave = g.Transform; float now_rotate = (float)GetRotate(arrayCoordinate[i].x, arrayCoordinate[i].y); Point p = new Point(arrayCoordinate[i].x + ecllpse_width, ecllpse_height - arrayCoordinate[i].y); int fontwidth = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Width; int fontheight = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Height; Matrix mtxRotate = g.Transform; p.X -= fontwidth / 2; p.Y -= fontheight / 2; mtxRotate.RotateAt(now_rotate, new PointF(p.X + fontwidth / 2, p.Y + fontheight / 2)); g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave; } } return map; } } }
const double RAD_ANG = 57.295779513082320876798154814105;void DrawBitmap(Bitmap bitmap, string text, Font font, int startAngle, int endAngle, Color color, float padding) { if(String.IsNullOrEmpty(text)) return; if (endAngle < startAngle) endAngle += 360; int width = bitmap.Width; int height = bitmap.Height; char[] textArray = text.ToArray(); int length = textArray.Length; double aAngle = (1.0d * (endAngle - startAngle)) / Math.Max(length - 1, 1); using (Graphics g = Graphics.FromImage(bitmap)) { Pen pen = new Pen(color, 4f); SolidBrush brushFont = new SolidBrush(color); g.SmoothingMode = SmoothingMode.HighQuality; g.PageUnit = GraphicsUnit.Pixel; SizeF sf = g.MeasureString(textArray[0].ToString(), font); double a = (width - 1 - sf.Width - padding) / 2 - pen.Width; double b = (height - 1 - sf.Height - padding) / 2 - pen.Width; double x0 = width / 2f; double y0 = height / 2f; g.DrawEllipse(pen, (float)(x0 - a) - (sf.Width + padding + pen.Width) / 2, (float)(y0 - b) - (sf.Height + padding + pen.Width) / 2, (float)(2 * a) + sf.Width + padding + pen.Width, (float)(2 * b) + sf.Height + padding + pen.Width); for (int i = 0; i < length; i++) { double r = (startAngle + (i * aAngle)) / RAD_ANG; double x = x0 + (float)(a * Math.Cos(r)); double y = y0 + (float)(b * Math.Sin(r)); double k = -(((b * b) * (x - x0)) / ((a * a) * (y - y0))); double kAngle = (Math.Atan(k) / (Math.PI / 180d)); //g.DrawLine(SystemPens.WindowText, (float)x0, (float)y0, (float)x, (float)y);//test Matrix matrixSave = g.Transform; Matrix matrixNow = g.Transform; sf = g.MeasureString(textArray[i].ToString(), font); PointF pointFont = new PointF((float)(x - sf.Width / 2), (float)(y - sf.Height / 2)); kAngle += x < x0 ? -180 : 180; kAngle += y < y0 ? 180 : 0; matrixNow.RotateAt((float)kAngle, new PointF((float)x, (float)y)); g.Transform = matrixNow; //g.DrawRectangle(SystemPens.WindowText, pointFont.X, pointFont.Y, sf.Width, sf.Height);//test g.DrawString(textArray[i].ToString(), font, brushFont, pointFont); g.Transform = matrixSave; } pen.Dispose(); brushFont.Dispose(); } }test codeprotected override void OnPaint(PaintEventArgs e) { string text = "中华人民共和国"; using (Font font = new System.Drawing.Font(Font.FontFamily, 18f, FontStyle.Bold)) { using (Bitmap bitmap = new Bitmap(Width, Height)) { DrawBitmap(bitmap, text, font, 150, 30, Color.Black, 10f); using (Graphics g = e.Graphics) { g.DrawImage(bitmap, 0, 0, Width, Height); } } } base.OnPaint(e); }
思路改了下 计算出来坐标 增加了验证功能。 内部的椭圆不是百分比计算 而是减少固定的长度 文字旋转率 是椭圆切线率 而不是到原点的角度。static Coordinate[] GetIntersection(double polygonWidth, double x, double y, double width, double height) { List<Coordinate> list = new List<Coordinate>(); double a, b, c, d, e, tan, A, B, C; tan = GetRotate(x, y); A = 1 - (double)Math.Pow(width, 2) / Math.Pow(height, 2); B = -2 * y; C = Math.Pow(x, 2) + Math.Pow(y, 2) - Math.Pow(polygonWidth, 2) + Math.Pow(width, 2); a = Math.Pow(A, 2); b = 2 * A * B; c = 2 * A * C + Math.Pow(B, 2) + 4 * Math.Pow(x, 2) * Math.Pow(width, 2) / Math.Pow(height, 2); d = 2 * B * C; e = Math.Pow(C, 2) - 4 * Math.Pow(x, 2) * Math.Pow(width, 2); double[] array = m4(a, b, c, d, e); for (int i = 0; i < array.Length; i++) { double y1 = array[i]; if (Math.Abs(y1) > height) continue; double x1 = width * Math.Sqrt(1 - Math.Pow(y1, 2) / Math.Pow(height, 2)); if ( Math.Round((double)Math.Pow(x1, 2) / Math.Pow(width, 2) + (double)Math.Pow(y1, 2) / Math.Pow(height, 2)) == 1) if (Math.Round((double)Math.Pow(x1 - x, 2) + (double)Math.Pow(y1 - y, 2)) == Math.Pow(polygonWidth,2)) list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) }); x1 = -1 * x1; if (Math.Round((double)Math.Pow(x1, 2) / Math.Pow(width, 2) + (double)Math.Pow(y1, 2) / Math.Pow(height, 2)) == 1) if (Math.Round((double)Math.Pow(x1 - x, 2) + (double)Math.Pow(y1 - y, 2)) == Math.Pow(polygonWidth, 2)) list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) }); } return list.ToArray(); ; }public static Bitmap DrawText2(string text) { int PolygonWidth = 33; int ecllpse_width = 150; int ecllpse_height = 100; int fontsize = 18; int firstpadding = 10; int secondpadding = 30; char[] texts = text.ToArray(); Coordinate[] arrayCoordinate = GetCoordinateArray(PolygonWidth, texts.Length, ecllpse_width - secondpadding, ecllpse_height - secondpadding); Bitmap map = new Bitmap(ecllpse_width * 2, ecllpse_height * 2); using (Graphics g = Graphics.FromImage(map)) { g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, (int)ecllpse_width * 2, (int)ecllpse_height * 2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot }, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2)); g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle(10, 10, (ecllpse_width - firstpadding) * 2, (ecllpse_height - firstpadding) * 2));
for (int i = 0; i < texts.Length; i++) { Matrix mtxSave = g.Transform; float now_rotate = (float)(-1 * Math.Pow(ecllpse_height - secondpadding, 2) * arrayCoordinate[i].x / (Math.Pow(ecllpse_width - secondpadding, 2) * arrayCoordinate[i].y)); now_rotate = (float)Math.Atan(now_rotate); if (arrayCoordinate[i].y > 0) now_rotate = (float)(-1 * now_rotate * 180 / Math.PI); else now_rotate = (float)(180 -1 * now_rotate * 180 / Math.PI); Point p = new Point(arrayCoordinate[i].x + ecllpse_width, ecllpse_height - arrayCoordinate[i].y); int fontwidth = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Width; int fontheight = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Height; Matrix mtxRotate = g.Transform; p.X -= fontwidth / 2; p.Y -= fontheight / 2; mtxRotate.RotateAt(now_rotate, new PointF(p.X + fontwidth / 2, p.Y + fontheight / 2)); //mtxRotate.RotateAt(now_rotate, new PointF(p.X + fontwidth / 2, p.Y)); g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave; } } return map; }
Graphics g2 = e.Graphics; PointF cnter = new PointF(300, 300);//中心点 float radX = 200F, radY = 130F, totalArcAng = 260;//x半径、y半径和所在弧角度 float minRat = 6f;//从边线向中心的移动因子 string text = "北京开天科技有限公司样品章"; // g2.DrawEllipse(pen, cnter.X - radX, cnter.Y - radY, radX * 2, radY * 2); Font font = new Font("宋体", 23F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(134))); double startAng = -90F - totalArcAng / 2f, endAng = -90f + totalArcAng / 2f; int count = text.Length; double accArcLen = 0.0, step = 0.5; int alCount = (int)Math.Ceiling(totalArcAng / step); double[] angArr = new double[alCount]; double[] arcLenArr = new double[alCount]; int num = 0; for (double i = startAng; i < endAng; i += step) { double angR = i * Math.PI / 180.0; double x = radX * Math.Cos(angR) + cnter.X, y = radY * Math.Sin(angR) + cnter.Y; angR = (i + step) * Math.PI / 180.0; double x2 = radX * Math.Cos(angR) + cnter.X, y2 = radY * Math.Sin(angR) + cnter.Y; accArcLen += Math.Sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)); angArr[num] = i + step; arcLenArr[num] = accArcLen; num++; } double arcPer = accArcLen / count; // for (int i = 0; i < count; i++) { double myt = i * arcPer + arcPer / 2.0; // double ang = 0.0; for (int p = 0; p < arcLenArr.Length - 1; p++) { if (arcLenArr[p] <= myt && myt <= arcLenArr[p + 1]) { ang = angArr[p + 1]; break; } } double angR = (ang * Math.PI / 180f); float x = radX * (float)Math.Cos(angR) + cnter.X, y = radY * (float)Math.Sin(angR) + cnter.Y; double qxang = Math.Atan2(radY * Math.Cos(angR), -radX * Math.Sin(angR)), fxang = qxang + Math.PI / 2.0; string c = text.Substring(i, 1); float w = g2.MeasureString(c, font).Width, h = g2.MeasureString(c, font).Height; // Matrix mat = g2.Transform; g2.TranslateTransform(-w / 2f * (float)Math.Cos(qxang), -w / 2f * (float)Math.Sin(qxang)); g2.TranslateTransform(h / minRat * (float)Math.Cos(fxang), h / minRat * (float)Math.Sin(fxang)); g2.TranslateTransform(x, y); g2.RotateTransform((float)(fxang * 180.0 / Math.PI - 90)); g2.TranslateTransform(-x, -y); g2.DrawString(c, font, Brushes.Black, x, y); g2.Transform = mat; }
/// <summary> /// /// </summary> /// <param name="g2"></param> /// <param name="font"></param> /// <param name="center"></param> /// <param name="radiusX"></param> /// <param name="radiusY"></param> /// <param name="totalArcAng">总的角跨度</param> /// <param name="minRat">从边线向中心的移动因子</param> /// <param name="text">字符串</param> /// <param name="top">是上边吗?</param> private void PaintOneText(Graphics g2, Font font, PointF center, float radiusX, float radiusY,// float totalArcAng, float minRat, string text, bool top) { double startAng = top ? -90F - totalArcAng / 2f : 90F - totalArcAng / 2f; double endAng = top ? -90f + totalArcAng / 2f : 90F + totalArcAng / 2f; int count = text.Length; double step = 0.5; int alCount = (int)Math.Ceiling(totalArcAng / step) + 1; double[] angArr = new double[alCount]; double[] arcLenArr = new double[alCount]; int num = 0; double accArcLen = 0.0; angArr[num] = startAng; arcLenArr[num] = accArcLen; num++; double angR = startAng * Math.PI / 180.0; double lastX = radiusX * Math.Cos(angR) + center.X; double laxtY = radiusY * Math.Sin(angR) + center.Y; for (double i = startAng + step; num < alCount; i += step) { angR = i * Math.PI / 180.0; double x = radiusX * Math.Cos(angR) + center.X, y = radiusY * Math.Sin(angR) + center.Y; accArcLen += Math.Sqrt((lastX - x) * (lastX - x) + (laxtY - y) * (laxtY - y)); angArr[num] = i; arcLenArr[num] = accArcLen; lastX = x; laxtY = y; num++; } double arcPer = accArcLen / count; // for (int i = 0; i < count; i++) { double arcL = i * arcPer + arcPer / 2.0; // double ang = 0.0; for (int p = 0; p < arcLenArr.Length - 1; p++) { if (arcLenArr[p] <= arcL && arcL <= arcLenArr[p + 1]) { ang = (arcL >= ((arcLenArr[p] + arcLenArr[p + 1]) / 2.0)) ? angArr[p + 1] : angArr[p]; break; } } angR = (ang * Math.PI / 180f); float x = radiusX * (float)Math.Cos(angR) + center.X, y = radiusY * (float)Math.Sin(angR) + center.Y; double qxang = Math.Atan2(radiusY * Math.Cos(angR), -radiusX * Math.Sin(angR)), fxang = qxang + Math.PI / 2.0; string c = text.Substring(top ? i : text.Length - 1 - i, 1); float w = g2.MeasureString(c, font).Width, h = g2.MeasureString(c, font).Height; if (top) { x += h * minRat * (float)Math.Cos(fxang); y += h * minRat * (float)Math.Sin(fxang); x += -w / 2f * (float)Math.Cos(qxang); y += -w / 2f * (float)Math.Sin(qxang); } else { x += (h * minRat + h) * (float)Math.Cos(fxang); y += (h * minRat + h) * (float)Math.Sin(fxang); x += w / 2f * (float)Math.Cos(qxang); y += w / 2f * (float)Math.Sin(qxang); } // Matrix mat = g2.Transform; g2.TranslateTransform(x, y); if (top) g2.RotateTransform((float)(fxang * 180.0 / Math.PI - 90)); else g2.RotateTransform((float)(fxang * 180.0 / Math.PI + 180 - 90)); g2.TranslateTransform(-x, -y); g2.DrawString(c, font, Brushes.Black, x, y); g2.Transform = mat; } } /// <summary> /// 绘制印章 /// 给定椭圆的中心,两个半径和文字所跨的角度来绘制。先求总的弧长,然后均分,每个字所占据的弧长相等。 /// 难点在于如何求弧长和角度的对应关系,我采取的办法是先求出一个对应表:从最小角度到最大角度,每0.5度 /// 递增,求出各段弧长累加即得到对应表。 /// 由弧长查角度的时候,从表中找到该弧长所在的闭区间,就得到对应的角度 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void PainYinZhang(object sender, PaintEventArgs e) { Graphics g2 = e.Graphics; PointF center = new PointF(300, 300);//中心点 float radiusX = 200F, radiusY = 130F;//x半径、y半径 Font font = new Font("宋体", 23F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(134))); // g2.DrawEllipse(pen, center.X - radiusX, center.Y - radiusY, radiusX * 2, radiusY * 2); PaintOneText(g2, font, center, radiusX, radiusY, 160, 0.20f, "山西开天电子有限公司", true); PaintOneText(g2, font, center, radiusX, radiusY, 90, -0.05f, "发票专用章", false); }
http://blog.csdn.net/alicehyxx/article/details/17009271
旋转Graphics对象,绘制文本。
关于旋转角度的计算和位置,其实都是数学问题,找本书翻翻看看就行了
则|OP|=√(x0^2+y0^2)=√(x0^2+b^2-b^2x0^2/a^2)=√(b^2+e^2x0^2),(e为椭圆离心率)
椭圆的离心率:e=c/a(0,1)(c,半焦距;a,半长轴(椭圆)/半实轴(双曲线) )
g.DrawEllipse(new Pen(Brushes.Red, 5), new RectangleF(0, 0, 100, 50));
那么他的内切文字要用你的公式的话 是怎么算呢?
如图
lib文件using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;namespace yangzhanglib
{
public class DrawString
{
/// <summary>
/// 根据角度 获取椭圆上一点的坐标
/// x2⒈/a2+y2/b2=1
/// y = x * tanα
/// </summary>
/// <param name="a">长半轴</param>
/// <param name="b">短半轴</param>
/// <param name="rotate">角度</param>
/// <returns></returns>
public static Point GetCoordinate(int a, int b, float rotate)
{
double x = 0, y = 0, tan = 0, Rad = 0;
if (Math.Abs(rotate) > 90)
Rad = (Math.Abs(rotate) - 90);
else
Rad = (90 - Math.Abs(rotate));
Rad = Rad * 2 * Math.PI / 360;
tan = Math.Tan(Rad); x = Math.Sqrt((double)1 / ((double)1 / (a * a) + (tan * tan) / (b * b)));
y = x * tan; if (rotate < 0)
x = 0 - x;
if (rotate > -90 && rotate < 90)
y = 0 - y;
x = a + x;
y = b + y; return new Point((int)Math.Round(x), (int)Math.Round(y));
} public static Bitmap DrawText(string text)
{
char[] texts = text.ToArray();
int beginRotate = -120;
int endRotate = 120;
float Rotate = (float)(endRotate - beginRotate) / (texts.Length - 1);
int ecllpse_width = 200;
int ecllpse_height = 150;
int fontsize = 18; Bitmap map = new Bitmap(ecllpse_width *2, ecllpse_height *2);
using (Graphics g = Graphics.FromImage(map))
{
g.FillRectangle(new SolidBrush(Color.White),new Rectangle(0,0,(int)ecllpse_width *2, (int)ecllpse_height *2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot}, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle((2 * ecllpse_width / 10), (2 * ecllpse_height / 10), (8 * ecllpse_width / 10) * 2, (8 * ecllpse_height / 10) * 2)); for (int i = 0; i < texts.Length; i++)
{
Matrix mtxSave = g.Transform;
float now_rotate = beginRotate + (Rotate * i);
Point p = GetCoordinate(13 * ecllpse_width / 20, 13 * ecllpse_height / 20, beginRotate + (Rotate * i)); Matrix mtxRotate = g.Transform;
p.X += ecllpse_width / 4;
p.Y += ecllpse_height / 4;
mtxRotate.RotateAt(beginRotate + (Rotate * i), new PointF(p.X + fontsize, p.Y + fontsize)); g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave;
}
}
return map;
}
}
}
页面cs代码using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using yangzhanglib;namespace yangzhang
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.CacheControl = "no-cache";
Response.ContentType = "image/jpeg";
using (System.Drawing.Bitmap map = DrawString.DrawText("北京开天科技有限公司样品章"))
{
byte[] bytes;
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
System.Drawing.Imaging.ImageCodecInfo[] icis = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.ImageCodecInfo ici = null;
foreach (System.Drawing.Imaging.ImageCodecInfo i in icis)
{
if (i.MimeType == "image/jpeg")
{
ici = i;
}
}
System.Drawing.Imaging.EncoderParameters ep = new System.Drawing.Imaging.EncoderParameters(1);
ep.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)90);
map.Save(ms, ici, ep); bytes = ms.ToArray(); ms.Close();
ms.Dispose();
}
Response.OutputStream.Write(bytes, 0, bytes.Length);
}
}
}
}
设计页面代码<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="yangzhang._Default" %>
非常感谢你的代码,有一点不怎么明白啊,就是定位他的切点位置的算法,我引用了你的切点算法GetCoordinate(),效果是变形的,不知道你下面这句代码写的含义是什么,求解
Point p = GetCoordinate(13 * ecllpse_width / 20, 13 * ecllpse_height / 20, beginRotate + (Rotate * i));
你可以把这句代码
g.Transform = mtxRotate;
先注释掉。跑出效果 看看。
然后根据效果来修正。
注释掉会全部乱掉了下面是我的业务代码,调用你的方法后是乱的
void DrawSealText(Graphics g, Brush myBrush)
{ if (JianJu == 0)
{
JianJu = 20;
}
//\r\n
TextSealValue = TextSealValue.Replace("\r\n", "");
int nChinese = TextSealValue.Length;
String myText = TextSealValue;
String[] chinese = new string[50];
int i; //将单个字保存在数组中
for (i = 0; i < nChinese; i++)
{
chinese[i] = myText.Substring(i, 1);
}
//定义字体大小
SizeF sf = g.MeasureString(chinese[0], textFont);
RectangleF rectF = new RectangleF(0, 0, sf.Width, sf.Height);
//定义字中心到圆心的半径
float r = Rectangle.Width / 2;
//定义字的位置
float xTemp, yTemp;
//定义字旋转角度
float angle; //圆心
Point cPoint = new Point();
cPoint.X = this.Rectangle.X + Rectangle.Width / 2;
cPoint.Y = Rectangle.Y + Rectangle.Height / 2;
//显示签章单位
//字体居中
// Set format of string.
StringFormat drawFormat = new StringFormat();
//drawFormat.Trimming = StringTrimming.EllipsisCharacter;
drawFormat.Alignment = StringAlignment.Center; //g.TranslateTransform(point.X, point.Y);//设置新的坐标原点
//g.RotateTransform(-50);//旋转270度
//g.DrawString(myText, myFont, myBrush, rectF, drawFormat);//以新的原点画文本
//g.ResetTransform();//还原坐点原点 //字数为偶数时
if (nChinese % 2 == 0)
{
//显示左半边字
for (i = 0; i < nChinese / 2; i++)
{
angle = (float)((nChinese / 2 - i - 1.0 / 2) * JianJu);
sf = g.MeasureString(chinese[i], TextFont);
rectF = new RectangleF(0, 0, sf.Width, sf.Height);
Point p = GetCoordinate(sf.Width, sf.Height , -angle);
//xTemp = (float)(cPoint.X - r * Math.Sin(angle * Math.PI / 180) - sf.Width / 2 * Math.Cos(angle * Math.PI / 180));
// yTemp = (float)(cPoint.Y - r * Math.Cos(angle * Math.PI / 180) + sf.Height / 2 * Math.Sin(angle * Math.PI / 180));
//g.TranslateTransform(xTemp, yTemp);//设置新的坐标原点
g.TranslateTransform(p.X, p.Y);
g.RotateTransform(-angle);//旋转
g.DrawString(chinese[i], TextFont, myBrush, rectF, drawFormat);//以新的原点画文本
g.ResetTransform();//还原坐点原点
} //显示右半边字
for (; i < nChinese; i++)
{
angle = (float)((i - nChinese / 2 + 1.0 / 2) * JianJu);
xTemp = (float)(cPoint.X + r * Math.Sin(angle * Math.PI / 180) - sf.Width / 2 * Math.Cos(angle * Math.PI / 180));
yTemp = (float)(cPoint.Y - r * Math.Cos(angle * Math.PI / 180) - sf.Height / 2 * Math.Sin(angle * Math.PI / 180));
sf = g.MeasureString(chinese[i], TextFont);
rectF = new RectangleF(0, 0, sf.Width, sf.Height);
g.TranslateTransform(xTemp, yTemp);//设置新的坐标原点
g.RotateTransform(angle);//旋转
g.DrawString(chinese[i], TextFont, myBrush, rectF, drawFormat);//以新的原点画文本
g.ResetTransform();//还原坐点原点
}
} //字数为奇数时
else
{
//显示左半边字和中间字
for (i = 0; i < (nChinese + 1) / 2; i++)
{
angle = (float)(((nChinese - 1) / 2 - i) * JianJu);
sf = g.MeasureString(chinese[i], TextFont);
rectF = new RectangleF(0, 0, sf.Width, sf.Height);
xTemp = (float)(cPoint.X - r * Math.Sin(angle * Math.PI / 180) - sf.Width / 2 * Math.Cos(angle * Math.PI / 180));
yTemp = (float)(cPoint.Y - r * Math.Cos(angle * Math.PI / 180) + sf.Height / 2 * Math.Sin(angle * Math.PI / 180));
g.TranslateTransform(xTemp, yTemp);//设置新的坐标原点
g.RotateTransform(-angle);//旋转
g.DrawString(chinese[i], TextFont, myBrush, rectF, drawFormat);//以新的原点画文本
g.ResetTransform();//还原坐点原点
}
//显示右半边字
for (; i < nChinese; i++)
{
angle = (float)((i - (nChinese - 1) / 2) * JianJu);//20 为字间距
xTemp = (float)(cPoint.X + r * Math.Sin(angle * Math.PI / 180) - sf.Width / 2 * Math.Cos(angle * Math.PI / 180));
yTemp = (float)(cPoint.Y - r * Math.Cos(angle * Math.PI / 180) - sf.Height / 2 * Math.Sin(angle * Math.PI / 180)); sf = g.MeasureString(chinese[i], TextFont);
rectF = new RectangleF(0, 0, sf.Width, sf.Height);
g.TranslateTransform(xTemp, yTemp);//设置新的坐标原点
g.RotateTransform(angle);//旋转
g.DrawString(chinese[i], TextFont, myBrush, rectF, drawFormat);//以新的原点画文本
g.ResetTransform();//还原坐点原点
}
} }
GetCoordinate 这个方法传入的width 和 height 如图所示。
和你传入的参数不一样。首先你要画一个椭圆,然后让文字在这个椭圆上的边上输出。
达到效果后,把传入的参数传小一点 就可以了。所以我会子啊我的代码里面乘以13/20。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;namespace yangzhanglib
{
public class DrawString
{
/// <summary>
/// 根据角度 获取椭圆上一点的坐标
/// x2⒈/a2+y2/b2=1
/// y = x * tanα
/// </summary>
/// <param name="a">长半轴</param>
/// <param name="b">短半轴</param>
/// <param name="rotate">角度</param>
/// <returns></returns>
public static Point GetCoordinate(int a, int b, float rotate)
{
double x = 0, y = 0, tan = 0, Rad = 0;
if (Math.Abs(rotate) > 90)
Rad = (Math.Abs(rotate) - 90);
else
Rad = (90 - Math.Abs(rotate));
Rad = Rad * 2 * Math.PI / 360;
tan = Math.Tan(Rad); x = Math.Sqrt((double)1 / ((double)1 / (a * a) + (tan * tan) / (b * b)));
y = x * tan; if (rotate < 0)
x = 0 - x;
if (rotate > -90 && rotate < 90)
y = 0 - y;
x = a + x;
y = b + y; return new Point((int)Math.Round(x), (int)Math.Round(y));
} public static Bitmap DrawText(string text)
{
char[] texts = text.ToArray();
int beginRotate = -120;
int endRotate = 120;
float Rotate = (float)(endRotate - beginRotate) / (texts.Length - 1);
int ecllpse_width = 200;
int ecllpse_height = 150;
int fontsize = 18; Bitmap map = new Bitmap(ecllpse_width *2, ecllpse_height *2);
using (Graphics g = Graphics.FromImage(map))
{
g.FillRectangle(new SolidBrush(Color.White),new Rectangle(0,0,(int)ecllpse_width *2, (int)ecllpse_height *2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot}, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle((2 * ecllpse_width / 10), (2 * ecllpse_height / 10), (8 * ecllpse_width / 10) * 2, (8 * ecllpse_height / 10) * 2)); for (int i = 0; i < texts.Length; i++)
{
Matrix mtxSave = g.Transform;
float now_rotate = beginRotate + (Rotate * i);
Point p = GetCoordinate(13 * ecllpse_width / 20, 13 * ecllpse_height / 20, beginRotate + (Rotate * i)); Matrix mtxRotate = g.Transform;
p.X += ecllpse_width / 4;
p.Y += ecllpse_height / 4;
mtxRotate.RotateAt(beginRotate + (Rotate * i), new PointF(p.X + fontsize, p.Y + fontsize));
g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave;
}
}
return map;
} public struct Coordinate
{
public int x;
public int y;
} /// <summary>
/// 获取角度
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static double GetRotate(double x, double y)
{
if(x < 0 && y < 0)
return -270 - Math.Atan2(y, x) * 180 / Math.PI;
else
return 90 - Math.Atan2(y, x) * 180 / Math.PI;
} /// <summary>
/// 一元1次方程求解
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="d"></param>
/// <param name="e"></param>
/// <returns></returns>
public static double m1(double a, double b)
{
return (-1 * b) / a;
} /// <summary>
/// 一元2次方程求解
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="d"></param>
/// <param name="e"></param>
/// <returns></returns>
public static double[] m2(double a, double b, double c)
{
if (a == 0) return new double[] { m1(b, c) };
if (c == 0) return new double[] { m1(a, b), 0 }; double Discriminant = b * b - 4 * a * c;
return new double[]{
(-1 * b + Math.Sqrt(Discriminant)) / (2 * a) ,(-1 * b - Math.Sqrt(Discriminant)) / ( 2 * a)
};
} /// <summary>
/// 盛金公式法 一元3次方程求解
/// 当A=B=0时,方程有一个三重实根。
/// 当Δ=B^2-4AC>0时,方程有一个实根和一对共轭虚根。
/// 当Δ=B^2-4AC=0时,方程有三个实根,其中有一个二重根。
/// 当Δ=B^2-4AC<0时,方程有三个不相等的实根。
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="d"></param>
/// <param name="e"></param>
/// <returns></returns>
public static double[] m3(double a, double b, double c, double d)
{
if (a == 0) return m2(b, c, d);
if (d == 0) return m2(a, b, c).Concat(new double[] { 0 }).ToArray(); //重根判别式
double A = b * b - 3 * a * c;
double B = b * c - 9 * a * d;
double C = c * c - 3 * b * d; //总判别式
double Discriminant = B * B - 4 * A * C; if (A == 0 && B == 0) return new double[] { -1 * b / 3 * a }; if (Discriminant > 0) {
double Y1 = A * b + 3 * a * (-1 * B + Math.Sqrt(Discriminant)) / 2;
double Y2 = A * b + 3 * a * (-1 * B - Math.Sqrt(Discriminant)) / 2;
return new double[] { -1 * b - (Math.Pow(Y1, 1.0 / 3.0) + Math.Pow(Y2, 1.0 / 3.0)) / 3 * a };
} if (Discriminant == 0) {
double K = B / A;
return new double[] { (-1 * b / a) + K, -1 * K / 2 };
} if (Discriminant < 0) {
double T = (2 * A * b - 3 * a * B) / (a * Math.Sqrt(Math.Pow(A, 3)));
double O = Math.Acos(T);
return new double[] {
(-1 * b - 2 * Math.Sqrt(A) * Math.Cos(O/3))/(3*a),
(-1 * b + Math.Sqrt(A) * (Math.Cos(O/3) + Math.Sqrt(3) * Math.Sin(O/3)))/(3*a),
(-1 * b + Math.Sqrt(A) * (Math.Cos(O/3) - Math.Sqrt(3) * Math.Sin(O/3)))/(3*a)
};
} return new double[] { };
}
/// 费拉里法 一元4次方程求解
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="d"></param>
/// <param name="e"></param>
/// <returns></returns>
public static double[] m4(double a, double b, double c, double d, double e)
{
if (a == 0) return m3(b, c, d, e);
if (e == 0) return m3(a, b, c, d).Concat(new double[] { 0 }).ToArray();
if (a != 1) {
b /= a;
c /= a;
d /= a;
e /= a;
} // Coefficients for cubic solver
double cb, cc, cd;
double discrim, q, r, RRe, RIm, DRe, DIm, dum1, ERe, EIm, s, t, term1, r13, sqR, y1, z1Re, z1Im, z2Re;
cb = -c;
cc = -4.0 * e + d * b;
cd = -(b * b * e + d * d) + 4.0 * c * e;
q = (3.0 * cc - (cb * cb)) / 9.0;
r = -(27.0 * cd) + cb * (9.0 * cc - 2.0 * (cb * cb));
r /= 54.0;
discrim = q * q * q + r * r;
term1 = (cb / 3.0);
if (discrim > 0)
{
// 1 root real, 2 are complex
s = r + Math.Sqrt(discrim);
s = ((s < 0) ? -Math.Pow(-s, (1.0 / 3.0)) : Math.Pow(s, (1.0 / 3.0)));
t = r - Math.Sqrt(discrim);
t = ((t < 0) ? -Math.Pow(-t, (1.0 / 3.0)) : Math.Pow(t, (1.0 / 3.0)));
y1 = -term1 + s + t;
}
else
{
if (discrim == 0)
{
r13 = ((r < 0) ? -Math.Pow(-r, (1.0 / 3.0)) : Math.Pow(r, (1.0 / 3.0)));
y1 = -term1 + 2.0 * r13;
}
else
{
q = -q;
dum1 = q * q * q;
dum1 = Math.Acos(r / Math.Sqrt(dum1));
r13 = 2.0 * Math.Sqrt(q);
y1 = -term1 + r13 * Math.Cos(dum1 / 3.0);
}
}
// Determined y1, a real root of the resolvent cubic.
term1 = b / 4.0;
sqR = -c + term1 * b + y1;
RRe = RIm = DRe = DIm = ERe = EIm = z1Re = z1Im = z2Re = 0;
if (sqR >= 0)
{
if (sqR == 0)
{
dum1 = -(4.0 * e) + y1 * y1;
if (dum1 < 0) //D and E will be complex
z1Im = 2.0 * Math.Sqrt(-dum1);
else
{ //else (dum1 >= 0)
z1Re = 2.0 * Math.Sqrt(dum1);
z2Re = -z1Re;
}
}
else
{
RRe = Math.Sqrt(sqR);
z1Re = -(8.0 * d + b * b * b) / 4.0 + b * c;
z1Re /= RRe;
z2Re = -z1Re;
}
}
else
{
RIm = Math.Sqrt(-sqR);
z1Im = -(8.0 * d + b * b * b) / 4.0 + b * c;
z1Im /= RIm;
z1Im = -z1Im;
}
z1Re += -(2.0 * c + sqR) + 3.0 * b * term1;
z2Re += -(2.0 * c + sqR) + 3.0 * b * term1; //At this point, z1 and z2 should be the terms under the square root for D and E
if (z1Im == 0)
{ // Both z1 and z2 real
if (z1Re >= 0)
{
DRe = Math.Sqrt(z1Re);
}
else
{
DIm = Math.Sqrt(-z1Re);
}
if (z2Re >= 0)
{
ERe = Math.Sqrt(z2Re);
}
else
{
EIm = Math.Sqrt(-z2Re);
}
}
else
{
r = Math.Sqrt(z1Re * z1Re + z1Im * z1Im);
r = Math.Sqrt(r);
dum1 = Math.Atan2(z1Im, z1Re);
dum1 /= 2; //Divide this angle by 2
ERe = DRe = r * Math.Cos(dum1);
DIm = r * Math.Sin(dum1);
EIm = -DIm;
} return new double[] {
-term1 + (RRe + DRe) / 2 + (RIm + DIm) / 2 ,
-(term1 + DRe / 2) + RRe / 2 + (-DIm + RIm) / 2,
-(term1 + RRe / 2) + ERe / 2 + (-RIm + EIm) / 2,
-(term1 + (RRe + ERe) / 2) - (RIm + EIm) / 2
};
} public static Coordinate[] GetIntersection(double polygonWidth, double x, double y, double width, double height)
{ List<Coordinate> list = new List<Coordinate>();
double a, b, c, d, e, tan, A, B, C;
tan = GetRotate(x, y); A = 1 - (double)Math.Pow(width, 2) / Math.Pow(height, 2);
B = -2 * y;
C = Math.Pow(x, 2) + Math.Pow(y, 2) - Math.Pow(polygonWidth, 2) + Math.Pow(width, 2);
a = Math.Pow(A, 2);
b = 2 * A * B;
c = 2 * A * C + Math.Pow(B, 2) + 4 * Math.Pow(x, 2) * Math.Pow(width, 2) / Math.Pow(height, 2);
d = 2 * B * C;
e = Math.Pow(C, 2) - 4 * Math.Pow(x, 2) * Math.Pow(width, 2);
double[] array = m4(a, b, c, d, e);
for (int i = 0; i < array.Length; i++)
{
double y1 = array[i];
if (Math.Abs(y1) > height) continue; double x1 = width * Math.Sqrt(1 - Math.Pow(y1, 2) / Math.Pow(height, 2));
list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) });
x1 = -1 * x1;
list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) });
}
return list.ToArray(); ;
} /// <summary>
/// 根据椭圆上的一点,求出它顺时针另外的一个点,使这2个点的距离等于一个定值
/// </summary>
/// <param name="polygonWidth"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public static Coordinate GetNextCoordinate(double polygonWidth, double x, double y, double width, double height)
{ double tan = GetRotate(x, y);
Coordinate[] array = GetIntersection(polygonWidth, x, y, width, height);
for (int i = 0; i < array.Length; i++)
{
double y1 = array[i].y ;
double x1 = array[i].x;
if (GetRotate(x1 , y1) >= tan)
return new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) };
}
return new Coordinate() { x = 0, y = 0 };
} /// <summary>
/// 根据椭圆上的一点,求出它逆时针另外的一个点,使这2个点的距离等于一个定值
/// </summary>
/// <param name="polygonWidth"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public static Coordinate GetPrevCoordinate(double polygonWidth, double x, double y, double width, double height)
{
double tan = GetRotate(x, y);
Coordinate[] array = GetIntersection(polygonWidth, x, y, width, height); for (int i = 0; i < array.Length; i++)
{
double y1 = array[i].y;
double x1 = array[i].x;
if (GetRotate(x1, y1) <= tan)
return new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) };
}
return new Coordinate() { x = 0, y = 0 };
} /// <summary>
/// 根据字数的个数,获取指定椭圆内的 等边多边形 各个顶点的直角坐标系的坐标,以数组形式返回
/// </summary>
/// <param name="polygonWidth"></param>
/// <param name="textLength"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public static Coordinate[] GetCoordinateArray(int polygonWidth, int textLength, int width, int height)
{
Coordinate[] result = new Coordinate[textLength];
if (textLength % 2 == 0)
{
//偶数个字符
int x = polygonWidth / 2;
int y = (int)Math.Sqrt(height * height * (1 - (x * x) / (width * width))); result[textLength / 2] = new Coordinate() { x = -1 * x, y = y };
result[(textLength / 2) - 1] = new Coordinate() { x = x, y = y };
for (int i = (textLength / 2) - 2; i >= 0; i--)
{
result[i] = GetPrevCoordinate(polygonWidth, result[i + 1].x, result[i + 1].y, width, height);
}
for (int i = (textLength / 2) + 1; i < textLength; i++)
{
result[i] = GetNextCoordinate(polygonWidth, result[i - 1].x, result[i - 1].y, width, height);
}
}
else
{
//奇数个字符
result[(textLength - 1) / 2] = new Coordinate() { x = 0, y = height }; for (int i = (textLength - 1) / 2 - 1; i >= 0; i--)
{
result[i] = GetPrevCoordinate(polygonWidth, result[i + 1].x, result[i + 1].y, width, height);
}
for (int i = (textLength - 1) / 2 + 1; i < textLength; i++)
{
result[i] = GetNextCoordinate(polygonWidth, result[i - 1].x, result[i - 1].y, width, height);
}
}
return result;
}
public static Bitmap DrawText2(string text)
{
int PolygonWidth = 43;
int ecllpse_width = 200;
int ecllpse_height = 150;
int fontsize = 18; char[] texts = text.ToArray();
Coordinate[] arrayCoordinate = GetCoordinateArray(PolygonWidth, texts.Length, ecllpse_width * 65 / 100, ecllpse_height * 65 / 100); Bitmap map = new Bitmap(ecllpse_width * 2, ecllpse_height * 2);
using (Graphics g = Graphics.FromImage(map))
{
g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, (int)ecllpse_width * 2, (int)ecllpse_height * 2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot }, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle((2 * ecllpse_width / 10), (2 * ecllpse_height / 10), (8 * ecllpse_width / 10) * 2, (8 * ecllpse_height / 10) * 2));
for (int i = 0; i < texts.Length; i++)
{
Matrix mtxSave = g.Transform;
float now_rotate = (float)GetRotate(arrayCoordinate[i].x, arrayCoordinate[i].y);
Point p = new Point(arrayCoordinate[i].x + ecllpse_width, ecllpse_height - arrayCoordinate[i].y);
int fontwidth = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Width;
int fontheight = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Height;
Matrix mtxRotate = g.Transform;
p.X -= fontwidth / 2;
p.Y -= fontheight / 2;
mtxRotate.RotateAt(now_rotate, new PointF(p.X + fontwidth / 2, p.Y + fontheight / 2));
g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave;
}
}
return map;
}
}
}
const double RAD_ANG = 57.295779513082320876798154814105;void DrawBitmap(Bitmap bitmap, string text, Font font, int startAngle, int endAngle, Color color, float padding)
{
if(String.IsNullOrEmpty(text))
return;
if (endAngle < startAngle)
endAngle += 360;
int width = bitmap.Width;
int height = bitmap.Height;
char[] textArray = text.ToArray();
int length = textArray.Length;
double aAngle = (1.0d * (endAngle - startAngle)) / Math.Max(length - 1, 1);
using (Graphics g = Graphics.FromImage(bitmap))
{
Pen pen = new Pen(color, 4f);
SolidBrush brushFont = new SolidBrush(color);
g.SmoothingMode = SmoothingMode.HighQuality;
g.PageUnit = GraphicsUnit.Pixel;
SizeF sf = g.MeasureString(textArray[0].ToString(), font);
double a = (width - 1 - sf.Width - padding) / 2 - pen.Width;
double b = (height - 1 - sf.Height - padding) / 2 - pen.Width;
double x0 = width / 2f;
double y0 = height / 2f;
g.DrawEllipse(pen, (float)(x0 - a) - (sf.Width + padding + pen.Width) / 2, (float)(y0 - b) - (sf.Height + padding + pen.Width) / 2, (float)(2 * a) + sf.Width + padding + pen.Width, (float)(2 * b) + sf.Height + padding + pen.Width);
for (int i = 0; i < length; i++)
{
double r = (startAngle + (i * aAngle)) / RAD_ANG;
double x = x0 + (float)(a * Math.Cos(r));
double y = y0 + (float)(b * Math.Sin(r));
double k = -(((b * b) * (x - x0)) / ((a * a) * (y - y0)));
double kAngle = (Math.Atan(k) / (Math.PI / 180d));
//g.DrawLine(SystemPens.WindowText, (float)x0, (float)y0, (float)x, (float)y);//test
Matrix matrixSave = g.Transform;
Matrix matrixNow = g.Transform; sf = g.MeasureString(textArray[i].ToString(), font);
PointF pointFont = new PointF((float)(x - sf.Width / 2), (float)(y - sf.Height / 2));
kAngle += x < x0 ? -180 : 180;
kAngle += y < y0 ? 180 : 0; matrixNow.RotateAt((float)kAngle, new PointF((float)x, (float)y));
g.Transform = matrixNow;
//g.DrawRectangle(SystemPens.WindowText, pointFont.X, pointFont.Y, sf.Width, sf.Height);//test
g.DrawString(textArray[i].ToString(), font, brushFont, pointFont);
g.Transform = matrixSave;
}
pen.Dispose();
brushFont.Dispose();
}
}test codeprotected override void OnPaint(PaintEventArgs e)
{
string text = "中华人民共和国";
using (Font font = new System.Drawing.Font(Font.FontFamily, 18f, FontStyle.Bold))
{
using (Bitmap bitmap = new Bitmap(Width, Height))
{
DrawBitmap(bitmap, text, font, 150, 30, Color.Black, 10f);
using (Graphics g = e.Graphics)
{
g.DrawImage(bitmap, 0, 0, Width, Height);
}
}
}
base.OnPaint(e);
}
思路改了下
计算出来坐标 增加了验证功能。
内部的椭圆不是百分比计算 而是减少固定的长度
文字旋转率 是椭圆切线率 而不是到原点的角度。static Coordinate[] GetIntersection(double polygonWidth, double x, double y, double width, double height)
{ List<Coordinate> list = new List<Coordinate>();
double a, b, c, d, e, tan, A, B, C;
tan = GetRotate(x, y); A = 1 - (double)Math.Pow(width, 2) / Math.Pow(height, 2);
B = -2 * y;
C = Math.Pow(x, 2) + Math.Pow(y, 2) - Math.Pow(polygonWidth, 2) + Math.Pow(width, 2);
a = Math.Pow(A, 2);
b = 2 * A * B;
c = 2 * A * C + Math.Pow(B, 2) + 4 * Math.Pow(x, 2) * Math.Pow(width, 2) / Math.Pow(height, 2);
d = 2 * B * C;
e = Math.Pow(C, 2) - 4 * Math.Pow(x, 2) * Math.Pow(width, 2);
double[] array = m4(a, b, c, d, e);
for (int i = 0; i < array.Length; i++)
{
double y1 = array[i];
if (Math.Abs(y1) > height) continue;
double x1 = width * Math.Sqrt(1 - Math.Pow(y1, 2) / Math.Pow(height, 2));
if ( Math.Round((double)Math.Pow(x1, 2) / Math.Pow(width, 2) + (double)Math.Pow(y1, 2) / Math.Pow(height, 2)) == 1)
if (Math.Round((double)Math.Pow(x1 - x, 2) + (double)Math.Pow(y1 - y, 2)) == Math.Pow(polygonWidth,2))
list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) }); x1 = -1 * x1;
if (Math.Round((double)Math.Pow(x1, 2) / Math.Pow(width, 2) + (double)Math.Pow(y1, 2) / Math.Pow(height, 2)) == 1)
if (Math.Round((double)Math.Pow(x1 - x, 2) + (double)Math.Pow(y1 - y, 2)) == Math.Pow(polygonWidth, 2))
list.Add(new Coordinate() { x = (int)Math.Round(x1), y = (int)Math.Round(y1) });
}
return list.ToArray(); ;
}public static Bitmap DrawText2(string text)
{
int PolygonWidth = 33;
int ecllpse_width = 150;
int ecllpse_height = 100;
int fontsize = 18;
int firstpadding = 10;
int secondpadding = 30; char[] texts = text.ToArray();
Coordinate[] arrayCoordinate = GetCoordinateArray(PolygonWidth, texts.Length, ecllpse_width - secondpadding, ecllpse_height - secondpadding); Bitmap map = new Bitmap(ecllpse_width * 2, ecllpse_height * 2);
using (Graphics g = Graphics.FromImage(map))
{
g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, (int)ecllpse_width * 2, (int)ecllpse_height * 2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 2) { DashStyle = DashStyle.Dot }, new Rectangle(0, 0, ecllpse_width * 2, ecllpse_height * 2));
g.DrawEllipse(new Pen(new SolidBrush(Color.Black), 4), new Rectangle(10, 10, (ecllpse_width - firstpadding) * 2, (ecllpse_height - firstpadding) * 2));
for (int i = 0; i < texts.Length; i++)
{
Matrix mtxSave = g.Transform;
float now_rotate = (float)(-1 * Math.Pow(ecllpse_height - secondpadding, 2) * arrayCoordinate[i].x / (Math.Pow(ecllpse_width - secondpadding, 2) * arrayCoordinate[i].y));
now_rotate = (float)Math.Atan(now_rotate);
if (arrayCoordinate[i].y > 0)
now_rotate = (float)(-1 * now_rotate * 180 / Math.PI);
else
now_rotate = (float)(180 -1 * now_rotate * 180 / Math.PI); Point p = new Point(arrayCoordinate[i].x + ecllpse_width, ecllpse_height - arrayCoordinate[i].y); int fontwidth = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Width;
int fontheight = (int)g.MeasureString(texts[i].ToString(), new Font("Arial", fontsize)).Height; Matrix mtxRotate = g.Transform;
p.X -= fontwidth / 2;
p.Y -= fontheight / 2;
mtxRotate.RotateAt(now_rotate, new PointF(p.X + fontwidth / 2, p.Y + fontheight / 2));
//mtxRotate.RotateAt(now_rotate, new PointF(p.X + fontwidth / 2, p.Y));
g.Transform = mtxRotate; g.DrawString(texts[i].ToString(), new Font("Arial", fontsize), new SolidBrush(Color.Black), p); g.Transform = mtxSave;
}
}
return map;
}
Graphics g2 = e.Graphics;
PointF cnter = new PointF(300, 300);//中心点
float radX = 200F, radY = 130F, totalArcAng = 260;//x半径、y半径和所在弧角度
float minRat = 6f;//从边线向中心的移动因子
string text = "北京开天科技有限公司样品章";
//
g2.DrawEllipse(pen, cnter.X - radX, cnter.Y - radY, radX * 2, radY * 2);
Font font = new Font("宋体", 23F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(134)));
double startAng = -90F - totalArcAng / 2f, endAng = -90f + totalArcAng / 2f;
int count = text.Length;
double accArcLen = 0.0, step = 0.5;
int alCount = (int)Math.Ceiling(totalArcAng / step);
double[] angArr = new double[alCount];
double[] arcLenArr = new double[alCount];
int num = 0;
for (double i = startAng; i < endAng; i += step)
{
double angR = i * Math.PI / 180.0;
double x = radX * Math.Cos(angR) + cnter.X, y = radY * Math.Sin(angR) + cnter.Y;
angR = (i + step) * Math.PI / 180.0;
double x2 = radX * Math.Cos(angR) + cnter.X, y2 = radY * Math.Sin(angR) + cnter.Y;
accArcLen += Math.Sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
angArr[num] = i + step;
arcLenArr[num] = accArcLen;
num++;
}
double arcPer = accArcLen / count;
//
for (int i = 0; i < count; i++)
{
double myt = i * arcPer + arcPer / 2.0;
//
double ang = 0.0;
for (int p = 0; p < arcLenArr.Length - 1; p++)
{
if (arcLenArr[p] <= myt && myt <= arcLenArr[p + 1])
{
ang = angArr[p + 1];
break;
}
}
double angR = (ang * Math.PI / 180f);
float x = radX * (float)Math.Cos(angR) + cnter.X, y = radY * (float)Math.Sin(angR) + cnter.Y;
double qxang = Math.Atan2(radY * Math.Cos(angR), -radX * Math.Sin(angR)), fxang = qxang + Math.PI / 2.0;
string c = text.Substring(i, 1);
float w = g2.MeasureString(c, font).Width, h = g2.MeasureString(c, font).Height;
//
Matrix mat = g2.Transform;
g2.TranslateTransform(-w / 2f * (float)Math.Cos(qxang), -w / 2f * (float)Math.Sin(qxang));
g2.TranslateTransform(h / minRat * (float)Math.Cos(fxang), h / minRat * (float)Math.Sin(fxang));
g2.TranslateTransform(x, y);
g2.RotateTransform((float)(fxang * 180.0 / Math.PI - 90));
g2.TranslateTransform(-x, -y);
g2.DrawString(c, font, Brushes.Black, x, y);
g2.Transform = mat;
}
/// <summary>
///
/// </summary>
/// <param name="g2"></param>
/// <param name="font"></param>
/// <param name="center"></param>
/// <param name="radiusX"></param>
/// <param name="radiusY"></param>
/// <param name="totalArcAng">总的角跨度</param>
/// <param name="minRat">从边线向中心的移动因子</param>
/// <param name="text">字符串</param>
/// <param name="top">是上边吗?</param>
private void PaintOneText(Graphics g2, Font font, PointF center, float radiusX, float radiusY,//
float totalArcAng, float minRat, string text, bool top)
{
double startAng = top ? -90F - totalArcAng / 2f : 90F - totalArcAng / 2f;
double endAng = top ? -90f + totalArcAng / 2f : 90F + totalArcAng / 2f;
int count = text.Length;
double step = 0.5;
int alCount = (int)Math.Ceiling(totalArcAng / step) + 1;
double[] angArr = new double[alCount];
double[] arcLenArr = new double[alCount];
int num = 0;
double accArcLen = 0.0;
angArr[num] = startAng;
arcLenArr[num] = accArcLen;
num++;
double angR = startAng * Math.PI / 180.0;
double lastX = radiusX * Math.Cos(angR) + center.X;
double laxtY = radiusY * Math.Sin(angR) + center.Y;
for (double i = startAng + step; num < alCount; i += step)
{
angR = i * Math.PI / 180.0;
double x = radiusX * Math.Cos(angR) + center.X, y = radiusY * Math.Sin(angR) + center.Y;
accArcLen += Math.Sqrt((lastX - x) * (lastX - x) + (laxtY - y) * (laxtY - y));
angArr[num] = i;
arcLenArr[num] = accArcLen;
lastX = x;
laxtY = y;
num++;
}
double arcPer = accArcLen / count;
//
for (int i = 0; i < count; i++)
{
double arcL = i * arcPer + arcPer / 2.0;
//
double ang = 0.0;
for (int p = 0; p < arcLenArr.Length - 1; p++)
{
if (arcLenArr[p] <= arcL && arcL <= arcLenArr[p + 1])
{
ang = (arcL >= ((arcLenArr[p] + arcLenArr[p + 1]) / 2.0)) ? angArr[p + 1] : angArr[p];
break;
}
}
angR = (ang * Math.PI / 180f);
float x = radiusX * (float)Math.Cos(angR) + center.X, y = radiusY * (float)Math.Sin(angR) + center.Y;
double qxang = Math.Atan2(radiusY * Math.Cos(angR), -radiusX * Math.Sin(angR)), fxang = qxang + Math.PI / 2.0;
string c = text.Substring(top ? i : text.Length - 1 - i, 1);
float w = g2.MeasureString(c, font).Width, h = g2.MeasureString(c, font).Height;
if (top)
{
x += h * minRat * (float)Math.Cos(fxang);
y += h * minRat * (float)Math.Sin(fxang);
x += -w / 2f * (float)Math.Cos(qxang);
y += -w / 2f * (float)Math.Sin(qxang);
}
else
{
x += (h * minRat + h) * (float)Math.Cos(fxang);
y += (h * minRat + h) * (float)Math.Sin(fxang);
x += w / 2f * (float)Math.Cos(qxang);
y += w / 2f * (float)Math.Sin(qxang);
}
//
Matrix mat = g2.Transform;
g2.TranslateTransform(x, y);
if (top)
g2.RotateTransform((float)(fxang * 180.0 / Math.PI - 90));
else
g2.RotateTransform((float)(fxang * 180.0 / Math.PI + 180 - 90));
g2.TranslateTransform(-x, -y);
g2.DrawString(c, font, Brushes.Black, x, y);
g2.Transform = mat;
}
} /// <summary>
/// 绘制印章
/// 给定椭圆的中心,两个半径和文字所跨的角度来绘制。先求总的弧长,然后均分,每个字所占据的弧长相等。
/// 难点在于如何求弧长和角度的对应关系,我采取的办法是先求出一个对应表:从最小角度到最大角度,每0.5度
/// 递增,求出各段弧长累加即得到对应表。
/// 由弧长查角度的时候,从表中找到该弧长所在的闭区间,就得到对应的角度
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PainYinZhang(object sender, PaintEventArgs e)
{
Graphics g2 = e.Graphics;
PointF center = new PointF(300, 300);//中心点
float radiusX = 200F, radiusY = 130F;//x半径、y半径
Font font = new Font("宋体", 23F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(134)));
//
g2.DrawEllipse(pen, center.X - radiusX, center.Y - radiusY, radiusX * 2, radiusY * 2);
PaintOneText(g2, font, center, radiusX, radiusY, 160, 0.20f, "山西开天电子有限公司", true);
PaintOneText(g2, font, center, radiusX, radiusY, 90, -0.05f, "发票专用章", false);
}