[C# 學習筆記]運用 GDI+ 的 Matrix 進行顯示圖形的平移和縮放


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM