小白都能看懂的两点连线曲线算法

有个需求要实现两点间多条连线,效果以下:git

这里的曲线能够直接经过二阶贝塞尔曲线来实现,曲线的控制点在两点连线的垂直线上,从直觉上我第一个想到的解法是要用到三角函数,因而就开始了如下推理过程github

基础知识

弧度 = 角度 * Math.PI / 180
角度 = 弧度 * 180 / Math.PI

Math.atan2(y, x): 返回从 点 (x,y) 到 x轴 的弧度
Math.cos(弧度): 直角三角形中,相邻直角边/斜边 的值
Math.sin(弧度): 直角三角形中,相对直角边/斜边 的值

二阶贝塞尔曲线:由两个数据点(A 和 B),一个控制点(C)来描述曲线状态
复制代码

画图

推理逻辑

目标:假定控制点 CA B 连线中点的距离是固定的 10, 计算出红色直角三角形的两个直角边的长度算法

  • 经过 Math.atan2(y, x) 计算 A(x0, y0) 点到 B(x1, y1) 点的连线与 X 轴的弧度,这里须要用 y1-y0 获得 y 值,x1-x0 获得 x 值,它的做用如图上的蓝色线,能够理解为把 x y 轴平移到 A 点,经过计算获得了 角1 的弧度 h
  • 经过三角形原理能够推断出 角1 === 角2
  • 计算 角2 的相对直角边长度:L1 = Math.sin(h) * 10
  • 计算 角2 的相邻直角边长度:L2 = Math.cos(h) * 10
  • A B 连线中点坐标的计算方式 mx = (x0+x1)/2 my = (y0+y1)/2
  • 控制点 C 的坐标最终为 cx = mx + L1 cy = mx - L2

最终算法

function getXY(a, b, distance) {
    const y = b.y - a.y;
    const x = b.x - a.x;
    const radian = Math.atan2(y, x);
    const L1 = Math.sin(radian) * distance;
    const L2 = Math.cos(radian) * distance;
    const mx = (a.x + b.x)/2;
    const my = (a.y + b.y)/2;
    const cx = mx + L1;
    const cy = mx - L2;
    return { x: cx, y: cy };
}

const A = { x: 10, y: 30 };
const B = { x: 300, y: 200 };
const C = getXY(A, B, 10);
复制代码

Echarts算法

按本身的想法写完以后,我在 Echarts 的源码中中看到了这种曲线的另一种超简单的算法apache

var x2 = (x0 + x1) / 2 - (y0 - y1) * 系数;
var y2 = (y0 + y1) / 2 - (x1 - x0) * 系数;
复制代码

简单的分析了一下,仍是经过三角形的方法,能够判断 C 的坐标能够和 A B 点坐标差值产生关联,在不一样的系数下能够获得全部中垂线上的点坐标bash

以上是从结果推算出来的结论,但它背后对应的公式原理,还不是很明白,但愿能有掘友提供一些思路echarts

参考资料


I'm Gafish 原创文章,首发于 个人博客,内容若有错误,还望指正,谢谢您的阅读。svg

相关文章
相关标签/搜索