【算法分析】QQ“一键退朝”之详细计算方法

原创 2015年12月23日 15:31:37

相信很多朋友和我一样很喜欢QQ上“一键退朝”的功能,就是把红点从它原本的地方拉走,消息提醒也就没有了。

这里写图片描述

直到如今我还是觉得这个功能很酷炫!于是想自己实现一番,经过一番调查知道拉伸其实就是由两个圆加上两条贝塞尔曲线组成的形状。

来看看腾讯设计师是怎么设计出来的吧:《QQ手机版 5.0“一键下班”设计小结》

看完了这个对实现思路有很大的帮助,可是我还是不能知道具体是怎么计算实现的,网上大部分的教程都是假想成了两个同样大小的圆来计算,这太取巧了!因为同样大小的圆两条外公切线是平行的,同一个圆上的公切点相连是会垂直于连心线的,但是大小不同的圆并没有这个特殊性!

另外网上也有很多仿照的项目,可是看算法看得头都大了也不明白为什么是这样算的!经过两天的研究,把初中数学(圆、三角函数等相关知识)好好复习了一遍,终于搞清楚了其中算法,现在跟我一起来看看吧!


1.得到连心线

通过观察可以发现,在“一键退朝”这个功能当中,有一个小圆固定在原来坐标位置不动的,只是半径会发生变化,另一个大圆是跟随着我们手指滑动到屏幕的位置来确定圆心坐标的,一般大圆的半径是固定的。

建立两圆的相对坐标系:

这里写图片描述

PS:在移动端的坐标系 y 轴是向下的。

假设某一个时刻,两圆的状态如图,我们现在可以确定的是小圆的圆心坐标 O 为(startXstartY),大圆的圆心坐标 P0 为 (x0, y0),以及小圆的半径 r 和大圆的半径 R

那么首先可以把连心线求出来!也就是 OP0 的距离。

线d=(x0startX)2+(y0startY)2

2.求切点坐标

复习一下初中数学:

两个外离的圆,一定有两条外公切线。若两圆半径相同,则两外公切线平行;否则相交于一点,且该点与两圆心在同一直线。

我们再作一张有公切线的图:

这里写图片描述

切点为 P1P2P3P4,我们现在目的就要求出这四个点,然后就能够在程序中画出切线。

整个算法最难的地方恐怕就是求这四个点了,我们需要借助作图来帮助计算,这之前还需要先复习下定理:

圆心和切点的连线一定垂直于过该点的公切线

首先过小圆圆心 O 作一条平行于 P1P2 的线,和 P0P2 相交于点 M ,可以得到 P1OMP2 为一个矩形,则 P2M=P1O=r ,又因为 P2P0=R ,所以 P0M=Rr ,那么

sinγ=sinMOP0=MP0OP0=Rrd

γ=MOP0=arcsinRrd

作连心线和 x 轴的夹角为 α

tanα=startYy0x0startX

α=arctanstartYy0x0startX

再作几个辅助点 ABCDAB 表示以大圆圆心为原点的坐标系的 x 轴的两端,CD 表示以小圆圆心为原点的坐标系的 x 轴的两端,

这里写图片描述

AB//CDP0OD=α

AP0O=α

P1OC=βP1O//P2P0

P2P0A=P1OC=β

OMP2P0OMP0=90°π2

β=π2γα

现在 β 求出来了,两圆的半径也已知,求 P1P2 的坐标是不是很简单?

P1.x=startXcosβrP1.y=startYsinβr

P2.x=x0cosβRP1.y=y0sinβR

3.求剩下两个切点的坐标

一开始我以为 P3P4 的算法和 P1P2 一样,就是把上面的减号换成加号就可以了。可是后来验证后发现不对, P3P4 不能直接使用 β 进行运算。

这里写图片描述

为了能愉快阅读,再来复习一下各种拉丁希腊符号叫法:
α 阿尔法 β 贝塔 γ 伽玛 δ 德尔塔 ε 伊普西隆 ζ 泽塔

如上图作辅助线。

P0ON=γ

δ+α=90°π2

δ=π2α

ONP0P4

γ+δ+ε=π2ε=π2γδ

ε+ζ=π2

ζ=π2ε=π2π2γδ=π2π2γπ2α

ζ=π2+γα

在前面 γα 已经求出来了!那么 P4 坐标也就不难了。

P3.x=startX+cosζrP3.y=startY+sinζr

P4.x=x0+cosζRP4.y=y0+sinζR

4.画贝塞尔曲线

把四个切点坐标求出来了,后面就简单了,现在就是以切线为原轴,画贝塞尔曲线了,不过我们还缺少一个控制点的坐标。

4.1 科普贝塞尔

怕有不清楚贝塞尔曲线的朋友,我科普一下先,简单来说就是求一段平滑曲线的公式。

如果我们把画一条直线分为进度100%的话,那么当进度为0%,12%,58%,74%时,画线的状态为(注意红色部分末的黑色端点,灰色部分为路径指示)

0125874

那么把所有时刻的黑点连接起来就构成了直线:

这里写图片描述

这个概念应该比较容易接受,好了继续。

二次贝塞尔曲线(最简单的贝塞尔曲线)的作法首先需要两个点确定一条直线,另外在直线外确定一点(即控制点),然后此时三点会形成三个线段,即下图的P0P2P0P1P1P2(其实不用关注 P0P2

这里写图片描述

这只是进度为0时候的状态,按照上面概念,当进度 t 从 0 变化到 100 时的某一个时刻,比如 30, 66 ,99,那么各个时刻P0P1P1P2的状态为

这里写图片描述这里写图片描述这里写图片描述

可以发现,在P0P1P1P2上有一直运动的两个点,我们将这两个点连接起来又形成一段新的线段,而在不同时刻,在这个新线段上同样会有一个运动的点,这个点也遵守 t 的变化。

这里写图片描述这里写图片描述这里写图片描述

把所有时刻的黄色点连接起来,就形成了二阶贝塞尔曲线。

这里写图片描述

还不能理解的可以看下这个视频 - > 《bezier curve原理》 只要看就好,听不懂英文的可以把声音关掉。

费这么大劲把二阶贝塞尔讲了一遍,我们这里其实也只用到了二阶,高阶我就不讲了,一通百通。

4.2.寻找控制点

那么现在线段已经能确定了,就是两条公切线线段(P1P2P3P4),那么控制点在哪呢?

这个其实有点靠猜了=。= 一开始我觉得应该在连心线的中点,其实实现后效果也还行,后来参照腾讯设计师的想法效果更好,他令 P1P2 的控制点为 P1P4 的中点,令P3P4 的控制点为 P2P3 的中点。

这里写图片描述

软件实现效果对比(左边控制点是连心线的中点,右边是腾讯设计师提出的控制点):

这里写图片描述 这里写图片描述

我个人觉得右边效果更好,也不得不佩服TX设计师的聪明才智,让我自己想可能永远也想不到。

至于求 P1P4P2P3 的中点不难吧?连四个坐标点都求出来了,直接算就可以了!


源码地址:https://github.com/Xieyupeng520/AZMetaBall(还会不断完善的,求星星^3^)

这里写图片描述


References:

《QQ手机版 5.0“一键下班”设计小结》

《【Android开源项目解析】QQ“一键下班”功能实现解析——学习Path及贝塞尔曲线的基本使用》

Github - MetaballLoading

本教程为了方便讲解有篡改原图,还望原图作者见谅!

版权声明:本文为博主原创文章,转载请标明原文地址以及作者(阿曌)。

贝塞尔曲线开发的艺术

贝塞尔曲线开发的艺术 一句话概括贝塞尔曲线:将任意一条曲线转化为精确的数学公式。 很多绘图工具中的钢笔工具,就是典型的贝塞尔曲线的应用,这里的一个网站可以在线模拟钢笔工具的使用: http://...
  • x359981514
  • x359981514
  • 2016年07月20日 10:06
  • 17851

QQ消除小红点(一键退朝)动画。

本来只是想写个可以拖动的小红点的,但写出乐趣来了,所以就多研究了研究,最后干脆封装了一下,可以实现给所有 View 添加黏贴效果。 GitHub 链接 效果如图: 首先需要了解贝塞尔...
  • wsh7365062
  • wsh7365062
  • 2016年09月05日 17:19
  • 393

【iOS效果集】实现QQ消除小红点(一键退朝)效果

QQ上黏黏的小红点很好玩有木有,于是自己也想实现一番,看到iOS实现的人比较少,Android的比较多,于是这个就用iOS来实现哈~ 效果图: 调试图: 其实从实现来讲,我是先实现第二...
  • XieYupeng520
  • XieYupeng520
  • 2016年01月28日 14:23
  • 3595

批处理文件——多个QQ一键登录

偶然看到有的同学登录PC的QQ,发现他有很多QQ,每登录一个要切换一个,虽然记住了密码,但还是不方便,于是想通过批处理来实现“一键登录”的功能。以下内容为本文假想,如有雷同,实属巧合!        ...
  • xuzewei_2
  • xuzewei_2
  • 2014年03月24日 13:55
  • 2933

《最优化计算方法》这门课中所有的方法在回归分析的比较与分析

现在我直接给出实验结果和代码,公式推导在前面几节已经给出,现在给出分析。   实验结果...
  • hlx371240
  • hlx371240
  • 2014年10月09日 18:52
  • 1572

php 实现qq一键登录

本帖最后由 佳人2012 于 2012-7-13 16:19 编辑 分享:PHP版QQ一键登录其实很简单,请看步骤!  因为各站有所不同,官方没有给出具体操作步骤,现在结合我的使用体验,分享网...
  • crisis111
  • crisis111
  • 2015年07月10日 11:15
  • 929

腾讯qq群推广“一键加群”的一个细节

刚才我们的新版产品要上线了,需要改一个“一键加群”的链接,我第一次使用这个功能,所以才被一个细节坑了,如下操作: 然后跳转到一个页面,”网页代码“地址类似: 时间仓促,复制了idkey...
  • sinat_22599079
  • sinat_22599079
  • 2014年12月26日 18:52
  • 2220

Android打开QQ临时会话以及一键加群的两种方法

一些Android应用中有时需要调用到qq的一些功能,本文主要介绍了通过qq号无需加好友进行临时会话的方法,以及用两种不同的方式一键调用手Q添加qq群的方法。...
  • foolfalcon
  • foolfalcon
  • 2015年01月06日 22:00
  • 6007

高仿qq‘一键下班’—让你的view‘黏’起来

qq手机客户端自5.0起有一个‘一键下班’的功能,qq聊天的消息数view可以拖拽,有一种黏黏的视觉效果,让手机控件更加生动,也增加了交互时的趣味性。最近在学习自定义控件的知识,所以试着实现了一下这个...
  • u012293381
  • u012293381
  • 2015年07月27日 11:26
  • 1795

android 一键添加QQ群 的实现步骤

1.浏览器访问QQ群网页  http://qun.qq.com/join.html 2.登陆自己的账户 3.复制android代码: /* * 发起添加群流程。群号:洛阳智慧安监(**...
  • shangxinlei88
  • shangxinlei88
  • 2015年04月13日 17:45
  • 4076
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【算法分析】QQ“一键退朝”之详细计算方法
举报原因:
原因补充:

(最多只允许输入30个字)