22

C# WPF动点任意移动气泡画法(解决方案使用到数学勾股定理、正弦定理、向量知识)。 -...

 6 years ago
source link: http://www.cnblogs.com/BarryJames/p/7885564.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C# WPF动点任意移动气泡画法(解决方案使用到数学勾股定理、正弦定理、向量知识)。

    许久没写博客了,最近在研究WPF下跟画板结合的轻量级气泡的画法,研发过程还是比较艰辛的(主要是复习了高中的数学知识,MMP全忘光了),这篇博客主要是提供一个思路给大家参考,如果有大神还有更好的解决方案可以不吝您的言论尽情留言。拿个这个类型的功能项目,首先分析可以假设气泡是由:椭圆/矩形/圆(椭圆的特例)和三角形组成,OK首先分步骤介绍研发步骤:

   第一:首先我的所有的图形都是基于矩阵画出来的,坐标轴起点是(0,0),假设一个拖拉点DynamicPoint (x,y),和一个固定点FixedPoint (m,n);由两点即可确定一个矩形大小,从里面画出内接图形和一个三角形;

              1、新建矩形  var TriagleRect = new Rect(FixedPoint, DynamicPoint);

              2、假设矩形之内存在一个等比例大小的圆,而圆是由圆心和半径组成的直线所划过的弧确定的,半径R,圆心CenterXY (p,q);相当于已知

              3、可以移动的点P设为:CurrentFixedPoint(s,t); 这个点是由鼠标捕获的相当于已知;

              4、由动点CurrentFixedPoint(s,t)向圆 M(圆心为CenterXY (p,q),半径R)作两条圆的切线,求出两切点F1(f1x,f1y)、F2(f2x,f2y)坐标值?

              如下图(做的图比较难看,做辅助之用)

                    

1072583-20171123155220415-1168369111.png

   到这边肯定很多人觉得很熟悉,没错这是高中的数学题,这边在研究的过程中研究了两种解决方案,下面简单的介绍下:

             如图,由圆心点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之后的效果。个人思路仅供参考。(这是原创文章,如有转载,请备注清楚)

     

1072583-20171123162438368-561061077.png
1072583-20171123162504961-743017838.png
1072583-20171123162540868-415747350.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK