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