許久沒寫博客了,最近在研究WPF下跟畫板結合的輕量級氣泡的畫法,研發過程仍是比較艱辛的(主要是複習了高中的數學知識,MMP全忘光了),這篇博客主要是提供一個思路給你們參考,若是有大神還有更好的解決方案能夠不吝您的言論盡情留言。拿個這個類型的功能項目,首先分析能夠假設氣泡是由:橢圓/矩形/圓(橢圓的特例)和三角形組成,OK首先分步驟介紹研發步驟:函數
第一:首先個人全部的圖形都是基於矩陣畫出來的,座標軸起點是(0,0),假設一個拖拉點DynamicPoint (x,y),和一個固定點FixedPoint (m,n);由兩點便可肯定一個矩形大小,從裏面畫出內接圖形和一個三角形;this
一、新建矩形 var TriagleRect = new Rect(FixedPoint, DynamicPoint);spa
二、假設矩形以內存在一個等比例大小的圓,而圓是由圓心和半徑組成的直線所劃過的弧肯定的,半徑R,圓心CenterXY (p,q);至關於已知code
三、能夠移動的點P設爲:CurrentFixedPoint(s,t); 這個點是由鼠標捕獲的至關於已知;orm
四、由動點CurrentFixedPoint(s,t)向圓 M(圓心爲CenterXY (p,q),半徑R)做兩條圓的切線,求出兩切點F1(f1x,f1y)、F2(f2x,f2y)座標值?blog
以下圖(作的圖比較難看,作輔助之用)ip
到這邊確定不少人以爲很熟悉,沒錯這是高中的數學題,這邊在研究的過程當中研究了兩種解決方案,下面簡單的介紹下:內存
如圖,由圓心點C向兩切點作垂直線,而後根據三角函數作輔助線PQ,QC得出斜邊PC長,由圖中能夠知道 博客
double Sine = R / AB; //求出正弦值數學
∠F1PC= Math.Round((Math.Asin(Sine) / Math.PI) * 180, 2);//把正弦值換算成角度
利用向量和向量模進行計算二元一次方程能夠得出F1,F2座標.
方程1:PF1向量=PC向量+CF1向量 ,這裏能夠得出一個關於F1的二元一次方程;
方程2:PF1向量的模=(PC平方+CF1平方)開根號,這裏能夠得出一個關於F1的二元二次方程;
由這兩個方程式能夠解出F1的座標值,同理也能夠得出F2的座標值;
也是如圖,方案1是稍微複雜了一點,比較不利於軟件當中的應用,這邊着重介紹第二種算出切點的可行性方案;
double MB = Math.Sqrt(Math.Pow(PC, 2) - Math.Pow(R, 2));//MB爲切線的長度
double Sine = R / AB; //求出正弦值
∠F1PC= Math.Round((Math.Asin(Sine) / Math.PI) * 180, 2);//把正弦值換算成角度
接下來跟方案1不一樣的地方是:我要讓圓心點按照角度∠F1PC進行順逆時針進行旋轉
1 //把移動點做爲圓心按照角度SineAngle旋轉,有方向,順逆時針 2 Vector vector = Point.Subtract(CenterXY, CurrentFixedPoint); 3 Matrix matrix = new Matrix(); 4 matrix.RotateAt(SineAngle, CurrentFixedPoint.X, CurrentFixedPoint.Y); 5 //轉換成單位向量1 6 var v = matrix.Transform(vector); 7 v.Normalize(); 8 9 Matrix matrix2 = new Matrix(); 10 matrix2.ScaleAt(_vector, _vector, CurrentFixedPoint.X, CurrentFixedPoint.Y); 11 var v2 = matrix2.Transform(v); 12 return v2;
通過上面旋轉,而後縮放到單位1的向量假設爲PF1' ,而後按比例放大到PF1的模長以後得出向量PF1,這樣就能夠得出F1點座標,同理得出F2;具體轉換以下:
1 //根據得到的向量值求出切點的座標值 2 var tmpPoint = Point.Add(P, SecondPoint); 3 var tmpPoint2 = Point.Add(P, ThirdPoint);
這樣就實現了移動動點P,F1,F2也會跟着角度進行實時變化,可是夾角不變,OK,如今動態的兩個點都已經確認出來了,接下來就能夠經過C#提供的方法進行連線,這樣就組成了一個三角形,這個三角形是由內圓心出發延伸至動點P的圖形。
1 //開始連線畫點 2 PathFigure PointPathFigure = new PathFigure(); 3 PointPathFigure.StartPoint = CurrentFixedPoint; 4 PointPathFigure.Segments.Add(new LineSegment(new Point(tmpPoint.X, tmpPoint.Y), true)); 5 PointPathFigure.Segments.Add(new LineSegment(new Point(tmpPoint2.X, tmpPoint2.Y), true)); 6 7 PathGeometry myPathGeometry = new PathGeometry(); 8 myPathGeometry.Figures.Add(PointPathFigure);
第二:兩個獨立圖形出來以後那就是組合圖形了,C#組合圖形提供了一個專門的方法:Geometry.Combine(Geometry geometry1, Geometry geometry2, GeometryCombineMode mode, Transform transform),很少說不懂得能夠查閱資料; 備註:ellipse 是第一個形狀,四個中心點分別位於矩陣的邊上;
1 //組合圖形 2 var geometry = Geometry.Combine(myPathGeometry, ellipse, GeometryCombineMode.Union, null); 3 4 this.DrawGeometry(streamGeometryContext, geometry);
效果圖以下:下面是任意移動動點P以後的效果。我的思路僅供參考。(這是原創文章,若有轉載,請備註清楚)