前言
公司项目需要做个画线缩放,我司称之为瞳距缩放,简而言之就是: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 }
看到这里,可以先揉揉眼睛,放松下...
全部代码已经贴上,下面是下载链接,有需要的朋友可以移步下载,欢迎点评,谢谢~