前言

公司项目需要做个画线缩放,我司称之为瞳距缩放,简而言之就是:2张图,从第一张图画一条线,再从第二个图画一条线,第二条线以第一条为基准,延长到一致的长度,并同比缩放图片;文字太枯燥,请先实例图

例子1:以皮卡丘为例,我要把路飞的拳头缩放到皮卡丘头那么大

例子2:以皮卡丘的基准,缩小路飞,与其身高一致

 

好了,相比看了上面的2个效果图,就明白了大致意思,这个demo可以获得,canvas里面的line如何顺着线条方向,无限延伸的解决方案,以及画线缩放等…

会运用到高中数学知识,三角函数知识点,所以不熟悉的朋友,需要先温习,这样吧,我带大家温习下,反正工作忙完了,写博客和网友分享经验是最愉悦的事儿…

 

三角函数必要知识点温习

tan:对边 / 临边      tana = bc / ac

sin:对边 / 斜边    sina = bc / ab

cos:临边 / 斜边     cosa = ac / ab

已知边 bc 、ac,求角a的度数    ∠a = math.atan(bc / ac);   这是最关键的,获取a的角度就解决了所有,起初我还是想了很久的,年龄一大,以前的事就记不得了,划重点这里

好了,三角函数的知识温习到这里就足矣了,想象一下,把这个三角形放到程序的坐标系中,细细品,假如用户随意画的线就是ab,在画好的基础上进行延长…….细细品….

 

画线缩放,难点就是,如何让第二条线延长

请看图

已知了a点b点的坐标,通过坐标系,就能换算出bc边和ac的长度

运用三角函数,∠a的度数就等于:math.atan(bc / ac);

拿到的∠a,一切都变得好说了

比如,ab=100

sina = bc / ab      —–>         sina = bc / 100     —->   bc = sina * 100

bc = 100 * math.sin(∠a)

cosa = ac / ab  —->   cosa = ac / 100  —->  ac = cosa * 100

ac = 100 * math.cos(∠a)

bc、ac边都拿到,相信朋友们能转换成point了

 

好了,上面都是知识点,很枯燥,程序员还是看代码吧,总归是要代码实现的

 1 <window x:class="pupildistancedemo.mainwindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:pupildistancedemo"
 7         mc:ignorable="d"
 8         windowstartuplocation="centerscreen"
 9         title="瞳距缩放" height="450" width="800">
10     <grid>
11         <canvas background="#0d1728" x:name="canvas">
12             <image source="2.jpg" x:name="img1" stretch="fill" width="300"  canvas.top="100" canvas.left="50" />
13             <image source="1.jpg" x:name="img2" stretch="fill" width="200" canvas.top="100" canvas.left="400" />
14         </canvas>
15         <stackpanel orientation="horizontal">
16             <button margin="5" verticalalignment="top" click="button_click">启动瞳距</button>
17             <button margin="5" verticalalignment="top" click="button_click_1">关闭瞳距</button>
18             <button margin="5" verticalalignment="top" click="button_click_2">瞳距计算</button>
19             <button margin="5" verticalalignment="top" click="button_click_3">重置</button>
20             <stackpanel verticalalignment="top">
21                 <textblock text="{binding elementname=img2,path=actualwidth}" foreground="red" />
22                 <textblock text="{binding elementname=img2,path=actualheight}" foreground="red" />
23             </stackpanel>
24         </stackpanel>
25     </grid>
26 </window>
  1 using system;
2 using system.collections.generic;
3 using system.linq;
4 using system.text;
5 using system.threading.tasks;
6 using system.windows;
7 using system.windows.controls;
8 using system.windows.data;
9 using system.windows.documents;
10 using system.windows.input;
11 using system.windows.media;
12 using system.windows.media.imaging;
13 using system.windows.navigation;
14 using system.windows.shapes;
15 
16 namespace pupildistancedemo
17 {
18     /// <summary>
19     /// mainwindow.xaml 的交互逻辑
20     /// </summary>
21     public partial class mainwindow : window
22     {
23         bool isleftbuttondown = false;
24         image image;
25 
26         bool ispupildistance = false;
27         size size;
28 
29         point currentpoint;
30 
31         public mainwindow()
32         {
33             initializecomponent();
34 
35             img1.mouseleftbuttondown += img_mouseleftbuttondown;
36             img1.mousemove += img_mousemove;
37             img1.mouseleftbuttonup += img_mouseleftbuttonup;
38 
39             img2.mouseleftbuttondown += img_mouseleftbuttondown;
40             img2.mousemove += img_mousemove;
41             img2.mouseleftbuttonup += img_mouseleftbuttonup;
42 
43             this.loaded += mainwindow_loaded;
44         }
45 
46         private void mainwindow_loaded(object sender, routedeventargs e)
47         {
48             size = new size(img2.actualwidth, img2.actualheight);
49         }
50 
51         private void img_mouseleftbuttonup(object sender, mousebuttoneventargs e)
52         {
53             isleftbuttondown = false;
54             image = null;
55         }
56 
57         private void img_mousemove(object sender, mouseeventargs e)
58         {
59             if (isleftbuttondown && sender is image imgc)
60             {
61                 var point = e.getposition(canvas);
62                 if (ispupildistance && imgc.tag is line line)
63                 {
64                     if (image.equals(imgc))
65                     {
66                         var x = point.x;
67                         var y = point.y;
68                         if (x > line.x1) x -= 2;
69                         else x += 2;
70                         if (y > line.y1) y -= 2;
71                         else y += 2;
72                         line.x2 = x;
73                         line.y2 = y;
74                     }
75                 }
76                 else if (sender is image image)
77                 {
78                     image.setvalue(canvas.leftproperty, point.x - currentpoint.x);
79                     image.setvalue(canvas.topproperty, point.y - currentpoint.y);
80                 }
81             }
82         }
83 
84         private void img_mouseleftbuttondown(object sender, mousebuttoneventargs e)
85         {
86             image = sender as image;
87             isleftbuttondown = true;
88             if (sender is image imgc)
89             {
90                 currentpoint = e.getposition(imgc);
91 
92                 if (ispupildistance)
93                 {
94                     if (imgc.tag is line line)
95                     {
96                         canvas.children.remove(line);
97                     }
98 
99                     line = new line();
100                     line.strokethickness = 2;
101                     line.stroke = new solidcolorbrush(colors.red);
102                     var point = e.getposition(canvas);
103                     line.x1 = point.x - 1;
104                     line.y1 = point.y - 1;
105                     line.x2 = line.x1;
106                     line.y2 = line.y1;
107                     canvas.children.add(line);
108                     imgc.tag = line;
109                 }
110             }
111         }
112 
113         private void button_click(object sender, routedeventargs e)
114         {
115             ispupildistance = true;
116         }
117 
118         private void button_click_1(object sender, routedeventargs e)
119         {
120             ispupildistance = false;
121         }
122 
123         /// <summary>
124         /// 计算瞳距
125         /// </summary>
126         /// <param name="sender"></param>
127         /// <param name="e"></param>
128         private void button_click_2(object sender, routedeventargs e)
129         {
130             var l1 = img1.tag as line;
131             var l2 = img2.tag as line;
132 
133             if (l1 == null || l2 == null)
134             {
135                 messagebox.show("请先 启用瞳距 ,再在图片上画线");
136                 return;
137             }
138 
139             //获取第一个图片的线
140             var length1 = distance(new point(l1.x1, l1.y1), new point(l1.x2, l1.y2));
141 
142             //获取第二个图片的线
143             var length2 = distance(new point(l2.x1, l2.y1), new point(l2.x2, l2.y2));
144 
145             //利用三角函数计算出以第一个图的线为基准,延长第二个图的线
146             var ac = math.abs(l2.x2 - l2.x1);
147             var bc = math.abs(l2.y2 - l2.y1);
148 
149             var jiaodu = math.atan(bc / ac);
150             var sinval = math.sin(jiaodu);
151             var cosval = math.cos(jiaodu);
152             var ac = cosval * length1;
153             var bc = sinval * length1;
154 
155             double xnew = 0, ynew = 0;
156             if (l2.x2 > l2.x1) xnew = ac + l2.x1;
157             else xnew = l2.x1 - ac;
158 
159             if (l2.y2 > l2.y1) ynew = l2.y1 + bc;
160             else ynew = l2.y1 - bc;
161 
162             l2.x2 = xnew;
163             l2.y2 = ynew;
164 
165             var wnew = length1 / (length2 / img2.actualwidth);
166             var hnew = length1 / (length2 / img2.actualheight);
167 
168             //以用户画的起点作为缩放中心
169             var x = (double)img2.getvalue(canvas.leftproperty);
170             var y = (double)img2.getvalue(canvas.topproperty);
171 
172             //起始点相对于图片的位置
173             var l2xtoimg = l2.x1 - x;
174             var l2ytoimg = l2.y1 - y;
175 
176             //获取起始点相对于图片的新位置,缩放后
177             var l2xtoimgnew = l2xtoimg / img2.actualwidth * wnew;
178             var l2ytoimgnew = l2ytoimg / img2.actualheight * hnew;
179 
180             img2.setvalue(canvas.leftproperty, l2.x1 - l2xtoimgnew);
181             img2.setvalue(canvas.topproperty, l2.y1 - l2ytoimgnew);
182 
183             //缩放
184             img2.width = wnew;
185             img2.height = hnew;
186         }
187 
188         /// <summary>
189         /// 计算点位之间的距离
190         /// </summary>
191         /// <param name="p1"></param>
192         /// <param name="p2"></param>
193         /// <returns></returns>
194         private double distance(point p1, point p2)
195         {
196             double result = 0;
197             result = math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
198             return result;
199         }
200 
201         /// <summary>
202         /// 重置
203         /// </summary>
204         /// <param name="sender"></param>
205         /// <param name="e"></param>
206         private void button_click_3(object sender, routedeventargs e)
207         {
208             list<line> l = new list<line>();
209             foreach (var item in canvas.children)
210             {
211                 if (item is line line)
212                 {
213                     l.add(line);
214                 }
215             }
216 
217             l.foreach(c => canvas.children.remove(c));
218 
219             img2.width = size.width;
220             img2.height = size.height;
221 
222             img2.setvalue(canvas.leftproperty, 380.0);
223             img2.setvalue(canvas.topproperty, 100.0);
224         }
225     }
226 }

 

看到这里,可以先揉揉眼睛,放松下…

全部代码已经贴上,下面是下载链接,有需要的朋友可以移步下载,欢迎点评,谢谢~