[C# 学习笔记]运用 GDI+ 的 Matrix 进行显示图形的平移和缩放
2024-10-21 23:11:40
C# 学习中,想尝试着做一个工控方面的上位机,可以读取CAD绘制的图形,然后把它显示出来,后面让运动控制器去走CAD里面的轨迹。
一、用netDXF 开源包,对DXF文件进行解析。解析后的直线、圆、圆弧、椭圆、多段线、曲线等图纸,分别用List存起来。
/// <summary>
/// 打开DXF文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_Open_Click(object sender, EventArgs e)
{ using (OpenFileDialog openFile = new OpenFileDialog())
{
openFile.Title = "加载DXF文件";
openFile.Filter = "dxf File(*.dxf)|*.dxf|ALL File(*.*)|*.*";
if (openFile.ShowDialog() == DialogResult.OK)
{
//获得文件路径
file = openFile.FileName;
//加载文件
dxf = DxfDocument.Load(file);
//解析文件
ImPort(file);
//生成绘制路径
BuildPath();
//绘制图形
this.MainPic.Image = PaintDXF(this.MainPic);
}
}
}
/// <summary>
/// 解析DXF文件
/// </summary>
/// <param name="fileName">要解析的文件名</param>
public void ImPort(string fileName)
{
lineList.Clear();
arcList.Clear();
cirList.Clear();
polylineList.Clear();
polylines.Clear(); // 解析多段线
foreach (LwPolyline lwPolyline in dxf.LwPolylines)
{
bool isHaveArc = false;
lwPolylineVertices.Clear();
lwPolylineVertices.AddRange(lwPolyline.Vertexes);
foreach (LwPolylineVertex lwPolylineVertex in lwPolylineVertices)
{
if (lwPolylineVertex.Bulge != 0)
{
isHaveArc = true;
break;
}
}
if (isHaveArc)
{
entityObjList.Clear();
//将LwPolyline实体炸开
entityObjList.AddRange(lwPolyline.Explode());
//分解多段线集合
foreach (EntityObject entityObject in entityObjList)
{
//如果是直线,就填加到直线集合
Line line_Tmp = entityObject as Line;
if (line_Tmp != null)
{
lineList.Add(line_Tmp);
}
//如果是圆弧,就填加到圆弧集合
Arc arc_Tmp = entityObject as Arc;
if (arc_Tmp != null)
{
arcList.Add(arc_Tmp);
}
}
}
else //多段线中没有圆弧,就把这个多段线添加到多段线List中
{
polylineList.Add(lwPolyline);
}
}
//解析直线
foreach (Line ln in dxf.Lines)
{
lineList.Add(ln);
}
//解析圆弧
foreach (Arc arc in dxf.Arcs)
{
arcList.Add(arc);
}
//解析圆
foreach (Circle cir in dxf.Circles)
{
cirList.Add(cir);
}
//解析椭圆
foreach (Ellipse elp in dxf.Ellipses)
{
//把椭圆转换成多段线
int precision = GetEllipseToPolylinesPercision(elp, 0.5);
polylineList.Add(elp.ToPolyline(precision));
}
//解析样条曲线
foreach (Spline spline in dxf.Splines)
{
//将样条曲线转换成多段线 (用绘制多段线的方式绘制)
int precision = GetSplineToPolylinesPrecision(spline, 0.5);
polylines.Add(spline.ToPolyline(precision));
}
//视窗中心坐标
viewcCenterX = dxf.Viewport.ViewCenter.X;
viewcCenterY = dxf.Viewport.ViewCenter.Y;
//视窗高度
viewcCenterH = dxf.Viewport.ViewHeight;
//根据视窗高度和显示框高度调整图形显示比例
m_fratio = (float)(MainPic.Size.Height / viewcCenterH); //显示数据
this.uiDataGridView1.DataSource = lineList;
this.dataGridView2.DataSource = arcList;
this.dataGridView3.DataSource = cirList;
this.dataGridView4.DataSource = polylines;
}
二、 把所有需要绘制图形(直线、圆弧、圆、椭圆、多段线、曲线、等)都添加到GraphicsPath 对象里面去
/// <summary>
/// 生成绘制路径
/// </summary>
private void BuildPath()
{
//清空之前存在的路径轨迹
graphicsPath.Reset();
// 直线 添加到绘制路径中
foreach (Line line in lineList)
{
PointF tf = Vector2PointF(line.StartPoint);
PointF tf2 = Vector2PointF(line.EndPoint);
//将线段添加到绘制路径对象
graphicsPath_tmp.AddLine(tf, tf2);
graphicsPath.AddPath(graphicsPath_tmp, false);
graphicsPath_tmp.Reset();
}
// 圆弧 添加到绘制路径中
foreach (Arc arc in arcList)
{
RectangleF ef3 = new RectangleF();
//半径
float r = Convert.ToSingle(arc.Radius);//* m_fratio;
//圆心坐标转换
PointF pf = Vector2PointF(arc.Center);
ef3.X = pf.X - r;
ef3.Y = pf.Y - r;
ef3.Width = 2f * r;
ef3.Height = 2f * r;
//起始角度
starAg = Convert.ToSingle(arc.StartAngle);
//扫描角度
sweepAg = Convert.ToSingle((360 - arc.StartAngle + arc.EndAngle) % 360);
graphicsPath_tmp.AddArc(ef3, starAg, sweepAg);
graphicsPath.AddPath(graphicsPath_tmp, false);
graphicsPath_tmp.Reset();
}
// 圆 添加到绘制路径中
foreach (Circle circle in cirList)
{
RectangleF rect = new RectangleF();
float r = Convert.ToSingle(circle.Radius);
//显示坐标转换
PointF pf = Vector2PointF(circle.Center); rect.X = pf.X - r;
rect.Y = pf.Y - r;
rect.Width = 2f * r;
rect.Height = 2f * r;
graphicsPath_tmp.AddEllipse(rect);
graphicsPath.AddPath(graphicsPath_tmp, false);
graphicsPath_tmp.Reset();
}
// 样条曲线转成的多段线添加到绘制路径中
foreach (Polyline polyline in polylines)
{
pointFs.Clear();
foreach (PolylineVertex vertex in polyline.Vertexes)
{
PointF pf = Vector2PointF(vertex.Position);
pointFs.Add(pf);
}
PointF[] potFs = pointFs.ToArray();
graphicsPath_tmp.AddLines(potFs);
if (polyline.IsClosed)
{
graphicsPath_tmp.CloseFigure();
}
graphicsPath.AddPath(graphicsPath_tmp, false);
graphicsPath_tmp.Reset();
}
// 轻量多段线 添加到绘制路径中
foreach (LwPolyline lwPolyline in polylineList)
{
pointFs.Clear();
foreach (LwPolylineVertex vertex in lwPolyline.Vertexes)
{
PointF pf = Vector2PointF(vertex.Position);
pointFs.Add(pf);
}
PointF[] potFs = pointFs.ToArray();
graphicsPath_tmp.AddLines(potFs);
if (lwPolyline.IsClosed)
{
graphicsPath_tmp.CloseFigure();
}
graphicsPath.AddPath(graphicsPath_tmp, false);
graphicsPath_tmp.Reset();
}
//定义一个矩阵,把纵坐标翻转
Matrix matrix = new Matrix(1, 0, 0, -1, 0, 0);
//定义矩阵的缩放向量
matrix.Scale(m_fratio, m_fratio);
//定义矩阵偏移向量 dxf文件的视窗中心放到显示的中心
matrix.Translate((float)viewcCenterX * -1, (float)viewcCenterY * -1);
//对路径进行矩阵转换
graphicsPath.Transform(matrix);
}
三、绘制路径(显示图形)
//新一个Matrix矩阵对象
Matrix translateMatrix = new Matrix(); /// <summary>
/// 图形绘制
/// </summary>
/// <param name="picture">绘制图形的控件</param>
/// <returns>返回图形绘制完成的图片</returns>
public Bitmap PaintDXF(PictureBox myPicBox)
{ //定义一个GDI+对象
using (Graphics graphics = Graphics.FromImage(image))
{
////设GDI对象的单位
//graphics.PageUnit = GraphicsUnit.Pixel;
// 设置为可剪辑区域
graphics.SetClip(displayRectangle);
//定义一个刷子 设置为黑色
SolidBrush brush = new SolidBrush(Color.Black);
//用上面定义的刷子填充整个图形
graphics.FillRectangle(brush, displayRectangle);
//定义绘制直线和曲线的笔 并设置为它的颜色和宽度(宽度为浮点数)
Pen pen1 = new Pen(Color.Blue, 2f);
Pen pen2 = new Pen(Color.FromArgb(50, 50, 50), 1f);
//画横格
for (int i = 1, rh = displayRectangle.Height; i < rh; i += 40)
{
graphics.DrawLine(pen2, 0, i, displayRectangle.Width, i);
}
//画竖格
for (int i = 1, rw = displayRectangle.Width; i < rw; i += 40)
{
graphics.DrawLine(pen2, i, 0, i, displayRectangle.Height);
}
//设置图形显示区中心为坐标原点
graphics.TranslateTransform(displayRectangle.Width / 2, displayRectangle.Height / 2);
//对绘制路径用定义的矩阵进行矩阵变换
graphicsPath.Transform(translateMatrix);
//绘制图象
graphics.DrawPath(pen1, graphicsPath);
} return image;
}
四、图形平移
/// <summary>
/// 鼠标按下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainPic_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
isLeftButton = true;
xStrat = e.X;
yStart = e.Y; }
/// <summary>
/// 鼠标拖动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainPic_MouseMove(object sender, MouseEventArgs e)
{
if (isLeftButton == true)
{
xEnd = e.X;
yEnd = e.Y;
m13 = xEnd - xStrat;
m23 = yEnd - yStart;
//重置矩阵
translateMatrix.Reset();
// 定义矩阵平移向量。
translateMatrix.Translate(m13, m23);
MainPic.Image = PaintDXF(this.MainPic);
m13 = m23 = 0;
xStrat = xEnd;
yStart = yEnd;
}
}
五、图形缩放
/// <summary>
/// 滚轮滚动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainPic_MouseWheel(object sender, MouseEventArgs e)
{
float fratio = 1f;
if (e.Delta < 0)
{
m_fratio *= 1f-0.05f;
fratio -= 0.05f;
}
else
{
m_fratio *= 1f+0.05f;
fratio += 0.05f;
}
if (m_fratio >= 10f)
{
m_fratio = 10f;
fratio = 1f;
}
if (m_fratio <= 0.1f)
{
m_fratio = 0.1f;
fratio = 1f;
}
//重置矩阵
translateMatrix.Reset();
//定义矩阵缩放向量
translateMatrix.Scale(fratio, fratio);
MainPic.Image = PaintDXF(this.MainPic);
}
最新文章
- 传播正能量&mdash;&mdash;做一个快乐的程序员
- Python or JavaScript 实现多级评论
- JAVA继承与覆写
- FineUI v3.3.2发布!目前最稳定版本,五年陈酿!
- putty ssh login linux
- 一些SVN 地址
- 【HDOJ】1224 Free DIY Tour
- StarTeam SDK 13 下载安装
- hdu What Are You Talking About(map)
- Flipping Parentheses~Gym 100803G
- leetCode刷题(找出数组里的两项相加等于定值)
- 傅里叶变换及其应用讲义(stanford_ee261)
- scrapy框架整理
- 小米手机安装mitmproxy证书
- mui---开发直播APP
- python摸爬滚打之day05----字典
- Math对象属性
- Python列表生成器
- [CMAKE] 详解CMakeLists.txt文件
- 第10章:MongoDB-CRUD操作--文档--修改--修改器