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;
}
}