画线缩放、瞳距缩放、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了
好了,上面都是知识点,很枯燥,程序员还是看代码吧,总归是要代码实现的
<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);
}
}
}
看到这里,可以先揉揉眼睛,放松下...
全部代码已经贴上,下面是下载链接,有需要的朋友可以移步下载,欢迎点评,谢谢~
画线缩放、瞳距缩放、Line延长到指定长度,内附效果,源码供应,解压就跑的更多相关文章
- Unity5中的粒子缩放(附测试源码)
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/49363241 作者:car ...
- iOS小画板画线总结
一:基本画线: 使用贝赛尔曲线画: //创建路径 UIBezierPath* aPath = [UIBezierPath bezierPath]; //设置线宽 aPath.lineWidth = 5 ...
- 用DirectX实现魔方(三)视角变换及缩放(附源码)
在本系列第一篇介绍过鼠标按键的功能,如下. 左键拖拽 - 旋转魔方 右键拖拽 - 变换视角 滚轮 - 缩放魔方 今天研究一下如何实现后面两个功能,用到的技术主要是Arcball,Arcball是实现M ...
- [修复] Firemonkey 画线问题(Android & iOS 平台)
问题:官方 QC 的一个 Firemonkey 移动平台画线问题: RSP-14309: [iOS & Android] Delphi 10.1 Berlin - drawing proble ...
- WPF画线问题,几千条以后就有明显的延迟了。
我现在是这么画的,class A { private GeometryGroup _lines; private Path _path; public A() { _path.Data = ...
- [stm32] 利用uc-gui封装画图和画线函数移植51上的模拟动画
>_<:这里的动画是黄色矩形区域中一个模仿俯视图的起重机运作动画,一个是模仿主视图的吊钩的运动.通过改变初始Init函数中的数据b_x,b_y实现矩形区域的移动.当实时采集时要首先根据起重 ...
- win32画线考虑去锯齿
整理日: 2015年2月16日 这几天一直在研究win32 SDk下画线去锯齿,之前一直用的QT的画线接口函数,里面有去锯齿的效果,可是突然项目要求不能用QT的只能用win32 SDK下的GDI画线接 ...
- Unity3D 画线插件 Vectrosity_Simple2DLine
Vectrosity是一个很方便的画线插件,用它我们可以画出2D,3D,贝塞尔,圆,椭圆等各种线条图案. :链接: http://pan.baidu.com/s/1pJjTFjt 密码: uesn 首 ...
- Openlayer 3 的画线测量长度
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- 概率分布的python实现
接上篇概率分布,这篇文章讲概率分布在python的实现. 文中的公式使用LaTex语法,即在\begin{equation}至\end{equation}的内容可以在https://www.codec ...
- Tensorflow常用函数说明
1.矩阵操作 1.1矩阵生成 这部分主要将如何生成矩阵,包括全0矩阵,全1矩阵,随机数矩阵,常数矩阵等 sess=tf.InteractiveSession() #x=tf.ones([2,3],tf ...
- 多进程使用同一log4j配置导致的日志丢失与覆盖问题
最近接手了一个流传很多手的魔性古早代码,追日志时发现有明显缺失.对log4j不熟,不过可以猜测日志出问题肯定和多进程使用同一个log4j配置有关.经多次排查,终于捋清了其中逻辑.本文对排查过程进行复盘 ...
- 基于 HTML5 + WebGL 的宇宙 3D 展示系统
前言 近年来随着引力波的发现.黑洞照片的拍摄.火星上存在水的证据发现等科学上的突破,以及文学影视作品中诸如<三体>.<流浪地球>.<星际穿越>等的传播普及,宇宙空间 ...
- C # socket 实例
同步客户端存储示例 下面的示例程序创建连接到服务器的客户端. 客户端使用一个同步套接字生成,因此,客户端应用程序的执行挂起,直到服务器返回响应. 应用程序将字符串发送到服务器 ...
- 英语口语考试资料Family
I Love my family 12 years ago, I was born in a happy family, there was a gentle father, a beautif ...
- Git基础用法
从远程仓库拉取代码: git clone https://xxxx.xxx.xx 进入拉取到代码的路径下,(文件夹中含有 .git 隐藏文件夹) 查看当前是否关联到远git代码管理 git statu ...
- Python中的Base64编码的加密与解密
Base64 可以干些啥? Base64编码的作用: 由于某些系统中只能使用ASCII字符.Base64就是用来将非ASCII字符的数据转换成ASCII字符的一种方法. 图片(and种子)base64 ...
- VMware修改默认开机方式
.首先删除已经存在的符号链接 ---------------------------------------------------------------------------------- rm ...
- 【开发者portal在线开发插件系列一】profile和基本上下行消息
前言: 开发者portal支持在线开发profile(即设备建模).在线开发插件.模拟应用管理设备.模拟设备上报数据接收命令.支持离线开发的profile和插件的上传部署,是合作伙伴快速集成设备.对接 ...