前言
公司项目需要做个画线缩放,我司称之为瞳距缩放,简而言之就是: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了
好了,上面都是知识点,很枯燥,程序员还是看代码吧,总归是要代码实现的
<Window x:Class="PupilDistanceDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PupilDistanceDemo"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="瞳距缩放" Height="" Width="">
<Grid>
<Canvas Background="#0D1728" x:Name="canvas">
<Image Source="2.jpg" x:Name="img1" Stretch="Fill" Width="" Canvas.Top="" Canvas.Left="" />
<Image Source="1.jpg" x:Name="img2" Stretch="Fill" Width="" Canvas.Top="" Canvas.Left="" />
</Canvas>
<StackPanel Orientation="Horizontal">
<Button Margin="" VerticalAlignment="Top" Click="Button_Click">启动瞳距</Button>
<Button Margin="" VerticalAlignment="Top" Click="Button_Click_1">关闭瞳距</Button>
<Button Margin="" VerticalAlignment="Top" Click="Button_Click_2">瞳距计算</Button>
<Button Margin="" VerticalAlignment="Top" Click="Button_Click_3">重置</Button>
<StackPanel VerticalAlignment="Top">
<TextBlock Text="{Binding ElementName=img2,Path=ActualWidth}" Foreground="Red" />
<TextBlock Text="{Binding ElementName=img2,Path=ActualHeight}" Foreground="Red" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace PupilDistanceDemo
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
bool isLeftButtonDown = false;
Image image; bool isPupilDistance = false;
Size size; Point currentPoint; public MainWindow()
{
InitializeComponent(); img1.MouseLeftButtonDown += Img_MouseLeftButtonDown;
img1.MouseMove += Img_MouseMove;
img1.MouseLeftButtonUp += Img_MouseLeftButtonUp; img2.MouseLeftButtonDown += Img_MouseLeftButtonDown;
img2.MouseMove += Img_MouseMove;
img2.MouseLeftButtonUp += Img_MouseLeftButtonUp; this.Loaded += MainWindow_Loaded;
} private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
size = new Size(img2.ActualWidth, img2.ActualHeight);
} private void Img_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isLeftButtonDown = false;
image = null;
} private void Img_MouseMove(object sender, MouseEventArgs e)
{
if (isLeftButtonDown && sender is Image imgc)
{
var point = e.GetPosition(canvas);
if (isPupilDistance && imgc.Tag is Line line)
{
if (image.Equals(imgc))
{
var x = point.X;
var y = point.Y;
if (x > line.X1) x -= ;
else x += ;
if (y > line.Y1) y -= ;
else y += ;
line.X2 = x;
line.Y2 = y;
}
}
else if (sender is Image image)
{
image.SetValue(Canvas.LeftProperty, point.X - currentPoint.X);
image.SetValue(Canvas.TopProperty, point.Y - currentPoint.Y);
}
}
} private void Img_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
image = sender as Image;
isLeftButtonDown = true;
if (sender is Image imgc)
{
currentPoint = e.GetPosition(imgc); if (isPupilDistance)
{
if (imgc.Tag is Line line)
{
canvas.Children.Remove(line);
} line = new Line();
line.StrokeThickness = ;
line.Stroke = new SolidColorBrush(Colors.Red);
var point = e.GetPosition(canvas);
line.X1 = point.X - ;
line.Y1 = point.Y - ;
line.X2 = line.X1;
line.Y2 = line.Y1;
canvas.Children.Add(line);
imgc.Tag = line;
}
}
} private void Button_Click(object sender, RoutedEventArgs e)
{
isPupilDistance = true;
} private void Button_Click_1(object sender, RoutedEventArgs e)
{
isPupilDistance = false;
} /// <summary>
/// 计算瞳距
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var l1 = img1.Tag as Line;
var l2 = img2.Tag as Line; if (l1 == null || l2 == null)
{
MessageBox.Show("请先 启用瞳距 ,再在图片上画线");
return;
} //获取第一个图片的线
var length1 = Distance(new Point(l1.X1, l1.Y1), new Point(l1.X2, l1.Y2)); //获取第二个图片的线
var length2 = Distance(new Point(l2.X1, l2.Y1), new Point(l2.X2, l2.Y2)); //利用三角函数计算出以第一个图的线为基准,延长第二个图的线
var AC = Math.Abs(l2.X2 - l2.X1);
var BC = Math.Abs(l2.Y2 - l2.Y1); var jiaodu = Math.Atan(BC / AC);
var sinVal = Math.Sin(jiaodu);
var cosVal = Math.Cos(jiaodu);
var ac = cosVal * length1;
var bc = sinVal * length1; double xnew = , ynew = ;
if (l2.X2 > l2.X1) xnew = ac + l2.X1;
else xnew = l2.X1 - ac; if (l2.Y2 > l2.Y1) ynew = l2.Y1 + bc;
else ynew = l2.Y1 - bc; l2.X2 = xnew;
l2.Y2 = ynew; var wnew = length1 / (length2 / img2.ActualWidth);
var hnew = length1 / (length2 / img2.ActualHeight); //以用户画的起点作为缩放中心
var x = (double)img2.GetValue(Canvas.LeftProperty);
var y = (double)img2.GetValue(Canvas.TopProperty); //起始点相对于图片的位置
var l2xToimg = l2.X1 - x;
var l2yToimg = l2.Y1 - y; //获取起始点相对于图片的新位置,缩放后
var l2xToimgnew = l2xToimg / img2.ActualWidth * wnew;
var l2yToimgnew = l2yToimg / img2.ActualHeight * hnew; img2.SetValue(Canvas.LeftProperty, l2.X1 - l2xToimgnew);
img2.SetValue(Canvas.TopProperty, l2.Y1 - l2yToimgnew); //缩放
img2.Width = wnew;
img2.Height = hnew;
} /// <summary>
/// 计算点位之间的距离
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
private double Distance(Point p1, Point p2)
{
double result = ;
result = Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
return result;
} /// <summary>
/// 重置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_Click_3(object sender, RoutedEventArgs e)
{
List<Line> l = new List<Line>();
foreach (var item in canvas.Children)
{
if (item is Line line)
{
l.Add(line);
}
} l.ForEach(c => canvas.Children.Remove(c)); img2.Width = size.Width;
img2.Height = size.Height; img2.SetValue(Canvas.LeftProperty, 380.0);
img2.SetValue(Canvas.TopProperty, 100.0);
}
}
}
看到这里,可以先揉揉眼睛,放松下...
全部代码已经贴上,下面是下载链接,有需要的朋友可以移步下载,欢迎点评,谢谢~