GDI+中,如何沿路径输入文字?
GraphicsPath中有一个方法是AddString(..),然后摆放的文字的坐标通过数学计算也可得出来,
问题是,这些字斜着摆放是怎么实现的呢?
/*====================================================================== 命名空间名: DrawContour CLR版本: 2.0.50727.1882 Mail: vxbb@vip. 491697374 Created by vxbb 2009-5-3 23:10:44 Site: <span style="color: #008000; text-decoration: underline;">http://aocdell.[/color] ======================================================================*/ // 等值线的定义 class Isogram { #region Members private int mTagNum; //标签数量 private float mInterval; //间隔 private float mLength; //等值线长度 private GeneralClass mGeneral; private TagStru mTagStru; //标签 private List<List<Point>> mPoints; //数据点 private List<Segment> mTagSegs; //标签线段 #endregion Members #region Properties public int TagNum { get { return mTagNum; } set { mTagNum = value; } } public float Interval { get { return mInterval; } set { mInterval = value; } } public float Length { get { return mLength; } set { mLength = value; } } public TagStru TagStru { get { if (mTagStru.Equals(null)) mTagStru = new TagStru(); return mTagStru; } set { if (!mTagStru.Equals(null)) mTagStru = value; } } public List<List<Point>> Points { get { if (mPoints == null) mPoints = new List<List<Point>>(); return mPoints; } set { RemoveAlllist(); if (value != null) { foreach (List<Point> list in value) AddPointList(list); } } } public List<Segment> TagSegs { get { if (mTagSegs == null) mTagSegs = new List<Segment>(); return mTagSegs; } set { RemoveAllSegment(); if (value != null) { foreach (Segment oSegment in value) AddSegment(oSegment); } } } #endregion Properties #region Constructors public Isogram() { mGeneral = new GeneralClass(); mTagSegs = new List<Segment>(); mPoints = new List<List<Point>>(); } #endregion Constructors #region Private Methods private void AddPointList(List<Point> list) { if (list == null) return; if (mPoints == null) mPoints = new List<List<Point>>(); mPoints.Add(list); } private List<Point> GetPointList(int index) { List<Point> list; if (mPoints == null) list = new List<Point>(); else list = mPoints[index]; return list; } private void RemoveList(List<Point> oldlist) { if (oldlist == null) return; if (mPoints != null) if (mPoints.Contains(oldlist)) mPoints.Remove(oldlist); } private void RemoveAlllist() { if (mPoints != null) mPoints.Clear(); } private void AddSegment(Segment newSegment) { if (newSegment.GetType() == null) return; if (mTagSegs == null) mTagSegs = new List<Segment>(); // if (!_tagSegs.Contains(newSegment)) //影响速度 mTagSegs.Add(newSegment); } private Segment GetSegment(int index) { Segment segment; if (mTagSegs == null) segment = new Segment(); else segment = mTagSegs[index]; return segment; } private void RemoveSegment(Segment oldSegment) { if (oldSegment.GetType() == null) return; if (mTagSegs != null) if (mTagSegs.Contains(oldSegment)) mTagSegs.Remove(oldSegment); } private void RemoveAllSegment() { if (mTagSegs != null) mTagSegs.Clear(); } #endregion Private Methods #region Public Methods //计算等值线注释点 public void ConIsoLine(List<Point> Points) { int count = Points.Count; List<Point> list = new List<Point>(); #region 计算等值线总长度 Point point1, point2; for (int i = 0; i < count - 1; i++) { point1 = Points[i]; point2 = Points[i + 1]; mLength += mGeneral.Distance(point1, point2); } #endregion #region 计算标签间隔长度 mInterval = (mLength-mTagStru.Width*mTagNum)/ (mTagNum + 1); if (mInterval <= 10) throw new Exception("标签数量设置错误"); float distance = 0; Point startPoint = Points[0]; #endregion #region 计算等值线注释点 for (int i = 0; i < count - 1; i++) { distance += mGeneral.Distance(startPoint, Points[i + 1]); if (distance > mInterval) { float R = mInterval - (distance - mGeneral.Distance(startPoint, Points[i + 1])); #region 计算标签 起点、终点 Segment lbPoint = new Segment(); list.Add(startPoint); lbPoint.StartPoint = mGeneral.GetNextPoint(startPoint, Points[i + 1], R, true); list.Add(lbPoint.StartPoint); mPoints.Add(list); float dis = mGeneral.Distance(lbPoint.StartPoint, Points[i + 1]); if (dis > mTagStru.Width) { lbPoint.EndPoint = mGeneral.GetNextPoint(lbPoint.StartPoint, Points[i + 1], mTagStru.Width, true); i++; } else { for (int j = i + 1; j < count - 1; j++) { dis = mGeneral.Distance(lbPoint.StartPoint, Points[j + 1]); if (dis > mTagStru.Width) { float r = mGeneral.Calculate(lbPoint.StartPoint, Points[j], Points[j + 1], mTagStru.Width); lbPoint.EndPoint = mGeneral.GetNextPoint(Points[j], Points[j + 1], r, true); i = j +1; break; } else if (dis == mTagStru.Width) { lbPoint.EndPoint = Points[j + 1]; i = j + 2; break; } } } #endregion if (lbPoint.EndPoint.IsEmpty) continue; mTagSegs.Add(lbPoint); startPoint = lbPoint.EndPoint; list = new List<Point>(); distance = 0; } else if (distance == mInterval) { #region 计算标签 起点、终点 Segment lbPoint = new Segment(); list.Add(startPoint); lbPoint.StartPoint = Points[i + 1]; list.Add(lbPoint.StartPoint); mPoints.Add(list); if (mGeneral.Distance(lbPoint.StartPoint, Points[i + 2]) > mTagStru.Width) { lbPoint.EndPoint = mGeneral.GetNextPoint(lbPoint.StartPoint, Points[i + 2], mTagStru.Width, true); i++; } else { for (int j = i + 2; j < count - 2; j++) { float dis = mGeneral.Distance(lbPoint.StartPoint, Points[j + 1]); if (dis > mTagStru.Width) { float r = mGeneral.Calculate(lbPoint.StartPoint, Points[j], Points[j + 1], mTagStru.Width); lbPoint.EndPoint = mGeneral.GetNextPoint(Points[j], Points[j + 1], r, true); i = j + 1; break; } else if (dis == mTagStru.Width) { lbPoint.EndPoint = Points[j + 1]; i = j + 2; break; } } } #endregion if (lbPoint.EndPoint.IsEmpty) continue; mTagSegs.Add(lbPoint); startPoint = lbPoint.EndPoint; list = new List<Point>(); distance = 0; } else { list.Add(startPoint); startPoint = Points[i + 1]; } if (mTagSegs.Count == mTagNum) { list.Add(startPoint); while (i < count) { list.Add(Points[i]); i++; } mPoints.Add(list); break; } } #endregion } #endregion Public Methods } }
/*====================================================================== 命名空间名: DrawContour CLR版本: 2.0.50727.1882 Mail: vxbb@vip. 491697374 Created by vxbb 2009-5-3 23:10:44 Site: <span style="color: #008000; text-decoration: underline;">http://aocdell.[/color] ======================================================================*/ class GeneralClass { //绘制矩形框及文字 public void RotationAngle(Point start, Point end, Graphics g, Isogram isogram) { float Heigth, Width; Heigth = isogram.TagStru.Heigth; Width = isogram.TagStru.Width; PointPair pair1 = new PointPair(); PointPair pair2 = new PointPair(); pair1 = GetPointPair(start, end, Heigth, true); pair2 = GetPointPair(end, start, Heigth, false); #region 两线的斜率、截距、角度、趋势和是否存在斜率 float k12, alpha12; float angle; bool flag = false; //是否存在斜率 bool IsincrX = false; //趋势 if (start.X < end.X) { IsincrX = true; flag = false; } else if (start.X == end.X) { IsincrX = false; flag = true; //不存在斜率 } else { IsincrX = false; flag = false; } #endregion #region 计算并返回转角 if (flag) //斜率不存在时 { if (start.Y > end.Y) angle = 90; else angle = 270; } else { k12 = (float)(end.Y - start.Y) / (end.X - start.X); alpha12 = (float)Math.Atan(k12); angle = (float)(180 / Math.PI * alpha12); } #endregion #region 根据有向线段(start,end)绘制文字。 if (IsincrX) { Point point = pair1.PointDown; g.TranslateTransform(point.X, point.Y); g.RotateTransform(angle); Pen pen = new Pen(Color.Blue, 1); RectangleF myRectangleF = new RectangleF(0, 0, Width, Heigth); Rectangle myRectangle = new Rectangle(0, 0, Convert.ToInt32(Width), Convert.ToInt32(Heigth)); //g.FillRectangle(new SolidBrush(Color.FromArgb(120, Color.Black)), myRectangle); g.DrawRectangle(pen, myRectangle); g.DrawString(isogram.TagStru.Text, isogram.TagStru.Font, Brushes.Red, myRectangleF); g.ResetTransform(); } else { Point point = pair2.PointUp; g.TranslateTransform(point.X, point.Y); g.RotateTransform(angle); Pen pen = new Pen(Color.Red, 1); RectangleF myRectangleF = new RectangleF(0, 0, Width, Heigth); Rectangle myRectangle = new Rectangle(0, 0, Convert.ToInt32(Width), Convert.ToInt32(Heigth)); //g.FillRectangle(new SolidBrush(Color.FromArgb(120, Color.Black)), myRectangle); g.DrawRectangle(pen, myRectangle); g.DrawString(isogram.TagStru.Text, isogram.TagStru.Font, Brushes.Blue, myRectangleF); g.ResetTransform(); } #endregion } //余玄定理 public float Calculate(PointF start, PointF mid, PointF end, float Length) { float alpha, beta, gamma;//定义角 PointF a1, a2;//定义向量a1,a2 a1 = new PointF(); a2 = new PointF(); a1.X = start.X - mid.X; a1.Y = start.Y - mid.Y; a2.X = end.X - mid.X; a2.Y = end.Y - mid.Y; float length01 = (float)Math.Sqrt(a1.X * a1.X + a1.Y * a1.Y); float length12 = (float)Math.Sqrt(a2.X * a2.X + a2.Y * a2.Y); alpha = (float)Math.Acos((a1.X * a2.X + a1.Y * a2.Y) / (length01 * length12));//可能有错误! beta = (float)Math.Asin(Math.Abs(Math.Sin(alpha) * length01 / Length));//由正玄定理得到B角 gamma = (float)Math.PI - alpha - beta; if (gamma <= 0.18) { return Length - length01; } float x = (float)Math.Abs(Length * Math.Sin(gamma) / Math.Sin(alpha));//由正玄定理的到所要求的边 return x; } //获取起点沿线段方向移动Length后的坐标,线段:(start-----end),Isforward计算方向 public Point GetNextPoint(Point start, Point end, float Length, bool Isforward) { #region 两线的斜率、截距、角度、趋势和是否存在斜率 float k12, b12, alpha12; bool flag = false; //是否存在斜率 bool IsincrX = false, IsincrY = false; //趋势 IsincrX = start.X < end.X ? true : false; IsincrY = start.Y < end.Y ? true : false; if (start.X == end.X) flag = true; #endregion #region 计算并返回指定点 Point point; if (flag) //斜率不存在时 { if (IsincrY) point = new Point(start.X, Convert.ToInt32(start.Y + Length)); else point = new Point(start.X, Convert.ToInt32(start.Y - Length)); } else { k12 = (float)(end.Y - start.Y) / (end.X - start.X); b12 = start.Y - k12 * start.X; alpha12 = (float)Math.Atan(k12); point = GetNextPoint(start, alpha12, Length, IsincrX, Isforward); } #endregion return point; } //获取指定点的下一个点,Isincrease指定直线趋势 ,Isforward计算方向 public Point GetNextPoint(Point start, float alpha, float Length, bool Isincrease, bool Isforward) { float deltaX, deltaY; //坐标增量 Point point; if (Isincrease) { float Cos = (float)Math.Cos(alpha); float Sin = (float)Math.Sin(alpha); deltaX = Cos * Length; deltaY = Sin * Length; } else { float Cos = (float)Math.Cos(alpha); float Sin = (float)Math.Sin(alpha); deltaX = -1 * Cos * Length; deltaY = -1 * Sin * Length; } try { if (Isforward) point = new Point(Convert.ToInt32(start.X + deltaX), Convert.ToInt32(start.Y + deltaY)); else point = new Point(Convert.ToInt32(start.X - deltaX), Convert.ToInt32(start.Y - deltaY)); } catch { return start; } return point; } //获取直线的起点对(方向颠倒时Isforward设置为false) public PointPair GetPointPair(Point start, Point end, float width, bool Isforward) { float k, alpha; if (start.X == end.X) { end.X += 1; } k = (float)(end.Y - start.Y) / (end.X - start.X); alpha = (float)Math.Atan(k); float xup, xdown, yup, ydown; if (start.X < end.X) { xup = start.X - (width / 2) * (float)Math.Sin(alpha); yup = start.Y + (width / 2) * (float)Math.Cos(alpha); xdown = start.X + (width / 2) * (float)Math.Sin(alpha); ydown = start.Y - (width / 2) * (float)Math.Cos(alpha); } else { xup = start.X + (width / 2) * (float)Math.Sin(alpha); yup = start.Y - (width / 2) * (float)Math.Cos(alpha); xdown = start.X - (width / 2) * (float)Math.Sin(alpha); ydown = start.Y + (width / 2) * (float)Math.Cos(alpha); } PointPair pointPair = new PointPair(); if (Isforward) { pointPair.PointUp = new Point(Convert.ToInt32(xup), Convert.ToInt32(yup)); pointPair.PointDown = new Point(Convert.ToInt32(xdown), Convert.ToInt32(ydown)); } else { pointPair.PointUp = new Point(Convert.ToInt32(xdown), Convert.ToInt32(ydown)); pointPair.PointDown = new Point(Convert.ToInt32(xup), Convert.ToInt32(yup)); } return pointPair; } //计算两点间的距离 public float Distance(Point point1, Point point2) { float length; length = (float)Math.Sqrt(Math.Pow((point2.Y - point1.Y), 2) + Math.Pow((point2.X - point1.X), 2)); return length; } }