画线缩放、瞳距缩放、Line延长到指定长度,内附效果,源码供应,解压就跑
前言
公司项目需要做个画线缩放,我司称之为瞳距缩放,简而言之就是: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 }
看到这里,可以先揉揉眼睛,放松下...
全部代码已经贴上,下面是下载链接,有需要的朋友可以移步下载,欢迎点评,谢谢~
上一篇: [译]C#8.0中一个使接口更加灵活的新特性-默认接口实现
下一篇: b站最好高口碑的Java教程