前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >你知道吗?圆弧有3种表达方式

你知道吗?圆弧有3种表达方式

作者头像
前端西瓜哥
发布于 2024-06-03 07:26:35
发布于 2024-06-03 07:26:35
49204
代码可运行
举报
运行总次数:4
代码可运行

大家好,我是前端西瓜哥。

圆弧是一条平面曲线,它是圆上两点间的一段,包含两个端点。

在做图形渲染的时候,我们需要设计好对应的数据结构,目前观测的常见的有三种表达。

这篇文章会对它们一一讲解分析。

圆心、半径 、起始角、结束角、方向

使用到的参数:

  • center: 圆心;
  • radius:半径;
  • starAngle:起始角;
  • endAngle:结束角;
  • sweep:是否为正方向(起点到终点走顺逆时针)。该参数可以去掉,因为可以通过交换 startAngle 和 endAngle 来做等价。

圆弧可以视作一个只绘制了部分线段的圆。

所以我们在原来圆形的圆心、半径参数的基础上,加上极坐标弧度表示的起点和终点,就能表达一段圆弧。

特别注意的是,我们需要提前定义好 图形所在画布的极坐标

  • angleStart:角度为 0 时对应哪个方向,通常为向右方向;
  • angleDir:极坐标的正方向。true 为顺时针,false 为逆时针。

Canvas 2D 使用了这种表达方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const center = { x: 150, y: 150 };
const radius = 100;
const startAngle = 0;
const endAngle = Math.PI * 2 * (5 / 7);

ctx.arc(center.x, center.y, radius, startAngle, endAngle);

绘制结果为:

起点、终点、半径、优弧、方向

用到的参数:

  • start:起点位置;
  • end:终点位置;
  • radius:半径;
  • largeArc:是否使用优弧(更长的那条弧);
  • sweep:正方向是顺逆方向,是否朝则正方向移动(起点到终点)。同样,这个 sweep 也是可要可不要,交换 start 和 end 也能表达。

已知起点、终点、半径,我们可以确定圆弧落在这两个圆的路径上。

起点和终点把圆分成两部分,接着我们需要看看是大弧还是小弧,确定走哪一部分。

最后是方向,起点到终点,应该走正方向(假设为顺时针方向)还是反方向。

至此,圆弧就确定好了。

SVG 的 Path 使用了这种表达方式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const start = { x: 100, y: 100 };
const end = { x: 250, y: 200 };
const radius = 95;
const sweep = true;
const largeArc = true;

const d = `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${
  largeArc ? 1 : 0
} ${sweep ? 1 : 0} ${end.x} ${end.y}`;

顺带一提,Path 还能表达椭圆弧。

渲染效果:

表达 2 这种方式没有圆心参数,但圆心位置还是要经常要用到的,比如渲染的时候还是要算出来,作为矩阵的参数的一部分。

求圆心的代码实现为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const getArc2Center = (
  start: Point,
  end: Point,
  radius: number,
  sweep: boolean,
  largeArc: boolean,
) => {
  const dist = distance(start, end);
  // 半径太小,无法构成圆。
  // 做特殊处理,radius 替换为 start 到 end 的距离除以 2
  // 此时圆心就是两点的中点
  if (radius * 2 < dist) {
    return {
      x: start.x / 2 + end.x / 2,
      y: start.y / 2 + end.y / 2,
    };
  }
  const cos = Math.min(dist / 2 / radius, 1);
  const dAngle = Math.acos(cos);
  const startToEndAngle = Math.atan((end.y - start.y) / (end.x - start.x));

  let angle = 0;
  if (sweep === largeArc) {
    angle = startToEndAngle - dAngle;
  } else {
    angle = startToEndAngle + dAngle;
  }

  return {
    x: start.x + radius * Math.cos(angle),
    y: start.y + radius * Math.sin(angle),
  };
};

原理是通过三角函数求起点到圆心对应的角,然后基于这个角度、起点位置、半径求出圆心位置。

起点、终点、凸度

使用到的参数:

  • start:起点位置;
  • end:结尾位置;
  • bulge:凸度,线条的凸出程度,对应 圆弧扫过的圆心角的 1/4 的正弦值

bulge 的符号表示方向,正数表示逆时针,负数表示顺时针。

我们知道,tan(45°) 的值为 1,所以当圆心角为 180度,它的 1/4 就是 45度,正弦值就是 1,即 180 度对应的凸度为 1。

然后正弦函数在 (-PI/2, PI/2) 区间是单调递增的,所以我们有:

凸度的绝对值小于 1 时,圆弧为劣弧;绝对值大于 1 时,圆弧为优弧;特别的,凸度为 0 时,表示的是直线

接着我们求圆弧的半径 radius。

根据凸度,我们通过反正弦求出圆心角 delta,然后我们作出下图。

半径 radius 的值为起点到终点距的一半,除以圆心角的一半(dist<start, end>/2) / sin(delta/2)

至此,我们把这种表达方式转换为了第二种表达方式,圆弧就表达出来了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const start = { x: 100, y: 100 };
const end = { x: 250, y: 200 };
const bulge: number = -1.6;

if (bulge === 0) {
  console.log('表达的是直线');
  return;
}

const sweep = bulge > 0 ? false : true;
const largeArc = Math.abs(bulge) > 1 ? true : false;
const sweepAngle = Math.atan(Math.abs(bulge)) * 4;
const radius = distance(start, end) / 2 / Math.sin(sweepAngle / 2);

渲染结果为:

这种表达方式我目前只在 AutoCAD 的多段线上见过。

优点:

  1. 同时表达圆弧和直线(凸度为 0);
  2. 参数更少,相对其它两种方式只要三个参数。

结尾

如果你想要改改参数调试代码,可以关注公众号,后台回复 “圆弧表达”,获取在线 demo 地址。

我是前端西瓜哥,欢迎关注我,学习更多平面几何知识。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端西瓜哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
平面几何:求直线线段的轮廓线
求线段的法向量,乘以线宽的一半,得到位移向量。然后让线段的两个点分别做两个方向的位移,得到多边形的 4 个顶点,将它们按照一定顺序连接起来得到多边形,这个多边形就是我们要求的轮廓多边形。
前端西瓜哥
2024/07/31
1390
平面几何:求直线线段的轮廓线
关于接口设计的一点想法
现在用户就可以发送`drawLine({x: 0,y: 0}, {x: 100,y: 100}, 'blue');`这样的消息。然后我们就画成了一条线。
4cos90
2021/02/18
4710
深度剖析一个弧形进度条的实现
Path 是 WPF 中的一个标记元素,用于绘制复杂的几何路径形状,而 ArcSegment 用于描述 Path 中两点之间的一条椭圆弧。两者结合可以很轻松的实现圆弧效果。
极炫小钢炮
2024/12/13
2440
深度剖析一个弧形进度条的实现
在两条直线相交处添加圆角,算法该如何实现?
然后基于圆心作两条直线的垂足得到两个点,这两个点就是圆弧起点和终点,然后确定方向就可以了。
前端西瓜哥
2024/06/17
2810
在两条直线相交处添加圆角,算法该如何实现?
Android 贝塞尔曲线解析
相信很多同学都知道“贝塞尔曲线”这个词,我们在很多地方都能经常看到。利用“贝塞尔曲线”可以做出很多好看的UI效果,本篇博客就让我们一起学习“贝塞尔曲线”。
老马的编程之旅
2022/06/22
1.3K0
Android 贝塞尔曲线解析
iOS开发-OpenGL ES画图应用思考题
这是一篇OpenGL ES的实战,紧接 入门教程3 学了OpenGL ES一段时间,用这个应用来练练手。 OpenGL ES系列教程在这里。 OpenGL ES系列教程的代码地址 - 你的star
落影
2018/04/27
1.1K0
iOS开发-OpenGL ES画图应用思考题
Android自定义系列——8.Path之贝塞尔曲线
一阶曲线原理: 一阶曲线是没有控制点的,仅有两个数据点(A 和 B),最终动态过程如下:
老马的编程之旅
2022/06/22
5790
Android自定义系列——8.Path之贝塞尔曲线
Android关于Path你所知道的和不知道的一切
张风捷特烈
2024/01/26
2980
Android关于Path你所知道的和不知道的一切
绘图-UIBezierPath
UIBezierPath是在 UIKit 中的一个类,继承于NSObject,可以创建基于矢量的路径.此类是Core Graphics框架关于path的一个OC封装。 所以 UIBezierPath 是基于 Core Graphics 实现的一项绘图技术。
進无尽
2018/09/12
1.4K0
绘图-UIBezierPath
史上最详细版 头文件biso.h,graphics.h,libbgi.a
BIOS.h是C语言里的一些头文件,包含了很多通用的函数和端口的定义,是为了让你在编写程序的时候方便调用的,在编译的时候会参与编译。
C you again 的博客
2020/09/15
1.6K0
高仿一个echarts饼图
饼图,很常见的一种图表,使用任何一个图表库都能轻松的渲染出来,但是,我司的交互想法千奇百怪,布局捉摸不透,本身饼图是没啥可变的,但是配套的图例千变万化,翻遍ECharts配置文档都还原不出来,那么有两条路可以选,一是跟交互说实现不了,说服交互按图表库的布局来,但是一般交互可能会对你灵魂拷问,为什么别人都能做出来,你做不出来?所以我选第二种,自己做一个得了。
街角小林
2022/06/15
1.1K0
高仿一个echarts饼图
平面几何:判断点是否在凸多边形内
在之前的 求两向量的夹角的文章 中我提到过,对于两个向量,我们可以利用叉积的符合右手定则,判断两个向量的位置关系。
前端西瓜哥
2024/05/15
2550
平面几何:判断点是否在凸多边形内
Android关于Path你所知道的和不知道的一切
零、前言 1.canvas本身提供了很多绘制基本图形的方法,普通绘制基本满足 2.但是更高级的绘制canvas便束手无策,但它的一个方法却将图形的绘制连接到了另一个次元 3.下面进入Path的世界,[注]:本文只说Path,关于绘制只要使用Canvas.drawPath(Path,Paint)即可 4.本文将对Path的所有API进行测试。 ---- 一、引:认识Path 例1.绘制网格 在Canvas篇我用Path画过一个网格辅助,在这里分析一下 moveTo相当于抬笔到某点,lineTo
张风捷特烈
2018/12/07
2.6K0
又来了!实现微信 “炸屎”大作战
大家好,我是秋风,近日,微信又发布了新功能(更新到微信8.0.6)。最火热的非"炸屎"功能莫属了,各种群里纷纷玩起了炸屎的功能。
秋风的笔记
2021/07/09
1.4K0
使用canvas绘制圆弧动画
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/j_bleach/article/details/86365888
j_bleach
2019/07/02
1.4K0
使用canvas绘制圆弧动画
POJ 2398--Toy Storage(叉积判断,二分找点,点排序)
Toy Storage Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6534 Accepted: 3905 Description Mom and dad have a problem: their child, Reza, never puts his toys away when he is finished playing with them. They gave Reza a rectangular box to put his toys in. Unfortunately, Reza is rebellious and obeys his parents by simply throwing his toys into the box. All the toys get mixed up, and it is impossible for Reza to find his favorite toys anymore. Reza’s parents came up with the following idea. They put cardboard partitions into the box. Even if Reza keeps throwing his toys into the box, at least toys that get thrown into different partitions stay separate. The box looks like this from the top:
Enterprise_
2019/02/20
2920
根据SVG Arc求出其开始角、摆动角和椭圆圆心
这时候我们通过矩阵运算得到了矩阵x1y1和矩阵cxcy,然后还有以下公式求开始角和摆动角:
ryzenWzd
2022/05/07
6010
根据SVG Arc求出其开始角、摆动角和椭圆圆心
平面几何:求内接或外切于圆的正多边形
思路是,让起点基于圆心旋转 PI * 2 / count 度数的倍数,执行 count - 1 次,拿到所有的点。
前端西瓜哥
2024/04/03
1780
平面几何:求内接或外切于圆的正多边形
Canvas系列(2):曲线图形
我们的代码是加在上一章最后的坐标系中的,如果直接使用arc画弧的话,那么起始点是上一个绘制的结束,也就是绘制坐标系的结束位置,为了让之前的代码的结束不在作为本次绘制的开始,我们使用了新的APIcontext.beginPath();,用来开启一个新的路径,路径相关的知识会在下一章跟大家分享。我们这里绘制了一个圆心是(150,75),半径是60,从0度到90度的弧。由上我们可以看出弧的角度是按照我们高中学的坐标系来的。所以,学习是有用的!!!
kai666666
2020/10/19
1.2K0
Canvas系列(2):曲线图形
手写原生代码专题 | 简易手写画板(二)
如视频所示,在这个示例中,我们用到了画布 canvas 相关的知识,比如创建画布、画圆形、画直线的基础知识,有了这些基础后,我们就能轻松完成本示例,示例效果如下视频所示。
前端达人
2021/07/16
1.6K0
相关推荐
平面几何:求直线线段的轮廓线
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档