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