许久没写博客了,最近在研究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以后的效果。我的思路仅供参考。(这是原创文章,若有转载,请备注清楚)