1. 程式人生 > >AutoCAD 凸度(bulge)的概念及使用WPF函式畫圖

AutoCAD 凸度(bulge)的概念及使用WPF函式畫圖

前言  凸度(bulge)是AutoCAD 中一個非常重要的概念,凸度控制著兩點之間弧度大小,弧度的方向。各種複雜的影象有可能就是成百上千的弧線組成的。從AutoCAD中匯出的資料也有該值,一般的形式為兩個點座標、一個凸度值。所以理解凸度的概念是處理AutoCAD 檔案重要的前提。本文會簡要介紹一下凸度的概念,同時會給出如何根據點座標和凸度劃線。

凸度演示程式

1 凸度的概念

凸度有兩個作用控制頂點弧度的大小和弧度的方向。如果通過兩個座標點畫弧,會有無數種可能性,所以必須引入第三個引數,來確定經過這兩點的唯一弧線,這個引數就是凸度。

凸度反應了兩點之間對應弧度的大小,它的具體值為這段弧所包含角度的1/4角度的正切值。兩點對應的弧度最大值為無限接近360度,凸度對應的值為接近90度的正切值,所以凸度最大值為無窮大。

仔細觀察上圖,圖B的弧度大於圖A的弧度,但是圖B的半徑小於圖A。

為什麼引入凸度值就能唯一確定弧線了?當凸度確定了,其實弧度對應的半徑就確定了。考察一下圖C,紅線標識的部分為一個等腰三角形,等腰三角形底邊長度和頂點角度確定了,就能唯一確定一個三角形大小(屬於初中幾何知識)。等腰三角形的兩個腰長度就是圓的半徑。

2 根據凸度計算及畫圖

不同的畫圖函式需要的引數也不同,我這裡根據具體的畫圖函式來講解,如何畫圖。

WPF繪圖上下文類為DrawingContext,這個類有一個繪圖函式

public abstract void DrawGeometry(Brush brush, Pen pen, Geometry geometry);

這個函式很簡單,但是這個函式可以畫任意圖形;因為Geometry 類功能太強大了,這個類可以描述任意幾何形狀。看一下如下程式碼:

 void AddArc(PathGeometry pathGeometry, System.Windows.Point point1, System.Windows.Point point2,  double bulge, double radius)
        {
            PathFigure pathFigure = new PathFigure();
            pathFigure.StartPoint = point1;//
起點 ArcSegment arcSegment = new ArcSegment(); arcSegment.Point = point2; //終點 //半徑 arcSegment.Size = new System.Windows.Size(radius, radius); //對應的角度 double radian = Math.Atan(bulge) * 4; double angle = radian * 180 / Math.PI; arcSegment.RotationAngle =Math.Abs(angle); //弧度的方向 順時針還是逆時針 arcSegment.SweepDirection = bulge>0? SweepDirection.Clockwise:SweepDirection.Counterclockwise; //是否大於180度 arcSegment.IsLargeArc = Math.Abs(bulge) > 1; pathFigure.Segments.Add(arcSegment); pathGeometry.Figures.Add(pathFigure); }

 上述程式碼根據兩點、凸度、圓半徑來實現畫圖。(半徑是根據前三個計算出來的,後面會講該演算法)

一個PathGeometry由一個或多個圖形暨PathFigure組成。PathFigure 就是一系列封閉或不封閉的線段或弧線組成。ArcSegment 代表一個弧線,將其加入到PathFigure,再將PathFigure加入到Geometry ,這樣就可以根據DrawGeometry畫出弧線了。函式有註釋,非常容易理解。

ArcSegment 還有一個引數就是圓的半徑。其實根據兩點、’凸度就可推匯出半徑,不知道為什麼ArcSegment 不替我們計算出來。下面講一下如何計算半徑。

3 根據凸度計算半徑

  public static double CalBulgeRadius(System.Windows.Point point1, System.Windows.Point point2, double bulge)
        {
            //計算頂點角度
            double cicleAngle = Math.Atan(bulge) * 4;

            //兩點之間的距離
            double pointLen = ImageHelper.CalPointLen(point1, point2);
            //根據正玄值反推
            double radius = (pointLen / 2) / Math.Sin(cicleAngle / 2);
            return Math.Abs(radius);
        }

看左圖,可知:頂點對應的角度的一半的正玄值就是 兩點之間的長度除以半徑。根據這一點就可以算出半徑。

3 計算圓點

上述函式雖然可以畫出圓弧,但是我們還是不知道圓心座標。這裡將一下如何推匯出圓心座標。

 

這裡有一個概念就是旋轉,將求解圓心座標分為兩個步驟。第一步在兩點之間取一點(點3),該點到點1的長度為半徑;第二步,將此點旋轉一定角度,就得到圓心座標。

求點3:

          //兩點之間的距離
            double pointLen = ImageHelper.CalPointLen(point1, point2);

            //半徑與兩點之間距離的比值
            double lenRate = radius / pointLen;
            System.Windows.Point midPoint = ImageHelper.GetMidPoint(point1, point2, lenRate);

internal static System.Windows.Point GetMidPoint(System.Windows.Point pt1, System.Windows.Point pt2, double lenRate) { Debug.Assert(lenRate>=0); if (lenRate == 1) return pt2; if (lenRate == 0) return pt1; System.Windows.Point result = new System.Windows.Point(); result.X = pt1.X + lenRate * (pt2.X - pt1.X); result.Y = pt1.Y + lenRate * (pt2.Y - pt1.Y); return result; }

根據幾何知識,可以得知:半徑與兩點之間的比率與點3的X座標與兩點的X座標比率一樣,這樣就能求出X座標。同理,可以求出Y座標。

旋轉:

點3以點1位圓心,旋轉一定角度,點3就落在圓心上了。旋轉的角度不難計算,頂點角度已知,又是等腰三角形,所以三角形的底角很容易算出。

旋轉計算涉及二維向量運算,不過.NET為我們提供了類Matrix。

 public static System.Drawing.Point RotationAt(System.Drawing.Point pointMove, System.Drawing.Point removeAt, 
            double rotateAngle, bool clockwise)
        {
            if (rotateAngle == 0)
                return pointMove;

            lock (matrix)
            {
                matrix.Reset();
                //設定旋轉的角度
                matrix.Rotate((float)(clockwise ? rotateAngle : -rotateAngle));

                //相對於removeAt旋轉
                System.Drawing.Point pt2 = new System.Drawing.Point(pointMove.X - removeAt.X, pointMove.Y - removeAt.Y);
                System.Drawing.Point[] pts = new System.Drawing.Point[] { new System.Drawing.Point(pt2.X, pt2.Y) };
                matrix.TransformPoints(pts);

                //再變換到圓點位置
                System.Drawing.Point result = new System.Drawing.Point(pts[0].X + removeAt.X, pts[0].Y + removeAt.Y);
                return result;
            }
        }

 後記:在二維座標上畫圖,需要有一定的幾何基礎和空間想象能力。初始接觸這類程式設計,還是有一定難度的。就需要我們補充一些幾何知識,同時多思考,總有一天會感覺豁然開朗。