跟月影学可视化
月影
前奇虎 360 奇舞团团长,可视化 UI 框架 SpriteJS 核心开发者,《JavaScript 王者归来》作者
30206 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 54 讲
跟月影学可视化
15
15
1.0x
00:00/00:00
登录|注册

05 | 如何用向量和坐标系描述点和线段?

绘制花瓣
随机因子
绘制树枝
坐标变换
旋转
长度和方向
加法
WebGL通过shader实现坐标转换
HTML、SVG、Canvas提供transform API
小试牛刀:问题1-3
坐标变换和向量描述的重要性
点乘、叉乘运算的特殊意义
计算机图形学的数学基础
实战演练:用向量绘制一棵树
向量运算
二维向量表示平面上的点和线段
坐标变换优化计算量
例子:绘制山和太阳
坐标系转换
HTML、SVG、Canvas、WebGL的通用坐标系
缺乏统一的方法论
陷入细节
推荐阅读
要点总结
向量运算的意义
如何用向量来描述点和线段?
如何用Canvas实现坐标系转换?
坐标系与坐标映射
为什么难以提升可视化项目能力?
如何用向量和坐标系描述点和线段?

该思维导图由 AI 生成,仅供参考

你好,我是月影。
为什么你做了很多可视化项目,解决了一个、两个、三个甚至多个不同类型的图表展现之后,还是不能系统地提升自己的能力,在下次面对新的项目时依然会有各种难以克服的困难?这是因为你陷入了细节里。
什么是细节?简单来说,细节就是各种纯粹的图形学问题。在可视化项目里,我们需要描述很多的图形,而描述图形的顶点、边、线、面、体和其他各种信息有很多不同的方法。并且,如果我们使用不同的绘图系统,每个绘图系统又可能有独特的方式或者特定的 API,去解决某个或某类具体的问题。
正因为有了太多可以选择的工具,我们也就很难找到最恰当的那一个。而且如果我们手中只有解决具体问题的工具,没有统一的方法论,那我们也无法一劳永逸地解决问题的根本
因此,我们要建立一套与各个图形系统无关联的、简单的基于向量和矩阵运算的数学体系,用它来描述所有的几何图形信息。这就是我在数学篇想要和你讨论的主要问题,也就是如何建立一套描述几何图形信息的数学体系,以及如何用这个体系来解决我们的可视化图形呈现的问题
那这一节课,我们先学习用坐标系与向量来描述基本图形的方法,从如何定义和变换图形的直角坐标系,以及如何运用向量表示点和线段这两方面讲起。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入浅出地介绍了如何用向量和坐标系描述点和线段,并强调了坐标系变换在图形绘制中的重要性。作者指出了在可视化项目中陷入细节的问题,强调了需要建立一套简单的基于向量和矩阵运算的数学体系来描述几何图形信息。文章详细介绍了浏览器常用的四种坐标系及其特点,并讨论了坐标系转换的重要性。通过Canvas为例,详细介绍了如何通过坐标系变换来简化图形绘制的过程,并且通过代码示例展示了坐标系变换的实际操作。最后,文章强调了理解直角坐标系的坐标变换对于简化计算量、优化代码和节省CPU运算时间的重要性。整体而言,本文内容涵盖了向量运算的基本原理和在图形绘制中的应用,对于理解计算机图形学的数学基础具有重要意义。 文章通过深入浅出的方式介绍了如何用向量和坐标系描述点和线段,并强调了坐标系变换在图形绘制中的重要性。作者指出了在可视化项目中陷入细节的问题,强调了需要建立一套简单的基于向量和矩阵运算的数学体系来描述几何图形信息。文章详细介绍了浏览器常用的四种坐标系及其特点,并讨论了坐标系转换的重要性。通过Canvas为例,详细介绍了如何通过坐标系变换来简化图形绘制的过程,并且通过代码示例展示了坐标系变换的实际操作。最后,文章强调了理解直角坐标系的坐标变换对于简化计算量、优化代码和节省CPU运算时间的重要性。整体而言,本文内容涵盖了向量运算的基本原理和在图形绘制中的应用,对于理解计算机图形学的数学基础具有重要意义。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《跟月影学可视化》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(32)

  • 最新
  • 精选
  • gltjk
    用向量的点乘、叉乘概念重新梳理小试牛刀的三题: 线段 A1B1 与线段 A2B2 的关系 { 如果 |A1B1| 或 |A2B2| 为 0 ,说明线段退化成点,无法判断关系 如果 A1B1·A2B2 为 0,说明夹角的余弦值为 0,二者垂直 如果 |A1B1×A2B2| 为 0,说明夹角的正弦值为 0,二者方向一致,可能平行也可能重合 { 如果 |A1B1×A1A2| 不为0,说明四点不共线,排除掉重合的情况,二者平行 } 其他情况即为既不平行也不垂直 } 点 P 到线段 AB 的距离 { 如果 |AB| 为 0,说明线段退化成点,|AP| 就是距离 如果 AP·AB: <0,说明 P 到 AB 的投影在线段 BA 的延长线上,∠PAB 为钝角,|AP| 就是距离 >|AB|,说明 P 到 AB 的投影在线段 AB 的延长线上,∠PBA 为钝角,|BP| 就是距离 其他情况,说明 P 到 AB 的投影在线段 AB 上,用 |AP×AB| 除以 |AB| 即可算出距离(外积模的几何意义 |absinθ| 就是平行四边形的面积,除以底得到高) } 点 P 与扫描角度 α 的关系 { 如果 α>2π,360°全覆盖,肯定能扫描到 如果 α<0,当前仅当点 P 与原点重合(即 P 的模为 0)时才能扫描到 把一四象限里的边上从原点出发的向量定为 A,二三象限里的定为 B(如果 α=0,虽然二者不在象限里,不过此时方向一致,无所谓了) 如果 |AxP|=0 或 |PxB|=0,说明 P 与 A 或 B 方向一致,刚好在边缘上,能扫描到 如果 α>π,可以假设坐标系上下翻转,有一个视角为 2π-α 的扫描器在扫描 P 关于 x 轴的映射 P',如果 P' 能被扫描到,说明 P 扫描不到,反之亦然 其余情况,如果要扫描到,必须要让从 A 到 B 逆时针扫描时经过 P,即 AxP 和 PxB 的方向都要与 z 轴正方向一致(用右手螺旋定则可以判断) } 代码如下(在之前的代码上修改的): https://codepen.io/gltjk/pen/eYJyOeR

    作者回复: 赞

    2020-07-02
    2
    36
  • gltjk
    今天的小试牛刀完全是中学数学啊…… 1. 用Δy/Δx计算斜率,平行是斜率相等,垂直是斜率乘积为-1。所以: 平行:Δy1/Δx1=Δy2/Δx2 垂直:(Δy1/Δx1)(Δy2/Δx2)=-1 为了避免出现分母为零(即平行于y轴,斜率无穷大)的情况,可以把除法换成乘法: 平行:Δx1Δy2-Δx2Δy1=0 垂直:Δx1Δx2+Δy1Δy2=0 不过要考虑一个边缘情况,如果两个线段有一个长度为零了(退化成点),就没法判断了。 2. 设线段为AB,其中A(x0,y0),B(x1,y1),点P(x2,y2) 正常思路是直接套用点到直线距离公式 d=|Ax0+By0+C|/Math.hypot(A,B),其中A、B、C为直线方程Ax+By+C=0里的系数,(x0,y0)为点的坐标。 用两点式写出直线方程,(y-y0)/(x-x0)=(y1-y0)/(x1-x0) 换成Ax+By+C=0的形式并排除分母为0的情况:(y1-y0)x+(x0-x1)y-(y1-y0)x0-(x0-x1)y0=0 观察系数得A=y1-y0,B=x0-x1,c=-(y1-y0)x0-(x0-x1)y0=-Ax0-By0 把A、B、C及(x2,y2)代入即可。 不过这里有个坑,给的不是直线,而是线段,线段是不能无限延长的,所以过点到直线作垂线与直线的交点不一定在线段上。 如果遇到这种情况,即角A或角B是钝角,就只能取PA和PB的较小值。 判断是否为钝角,可以用邻边平方和减去对边平方,结果为负数说明是钝角(正数是锐角,零是直角——刚好就是勾股定理了)。 另外,还有一个边缘情况,就是线段的两个点重合,与第一题不同,这时候的距离还是可以算的(此时PA=PB)。 3. 模仿文中思路用反正切函数Math.atan2()取到范围是[-PI, PI]的角度值,然后与扫描范围比较即可。 这里我把扫描范围扩展为任意实数的角度,并允许扫描到原点(如果角度为负则只能扫描到原点)。 然后对扫描范围的一半θ进行分类讨论: 超过π,说明360°全方位覆盖,肯定扫描得到; 没到π/2,扫描范围在[-π,0]之中,直接和反正切值比较即可; 其余情况,扫描范围起点在第四象限,终点在第三象限,被扫描的点如果在三四象限要大于起点或小于终点,如果在一二象限肯定能扫描到(也肯定大于起点)。 综上,因为数字比较多,这次代码用TS完成,同时顺便体验了一下Vue 3的Composition API: https://codepen.io/gltjk/pen/OJMOOJR

    作者回复: 用代数方法当然也能做,不过这样又要判断开方符号又要判断无穷大,可能还有其他特殊情况非常繁琐。既然我们这一节讲了向量,你试着用向量思路去解决,会发现十分简单。

    2020-07-01
    5
  • 仿佛回到了中学的解析几何题,感谢老师讲解向量的两个含义,但我对向量有些自己的理解,正好有肋于解决老师今天的思考题,下面说说我的思路: 1.1:若对此题做一个等效替代的话,其实不必拘泥于线段,可以延伸到线段所在的直线,这两条直线是否平行或垂直与原来的两条线段的关系是一致的 1.2:直线的关系可以理解为方向上的关系,既然向量可以表示方向,那么此题就可以进一步用向量来替代原来的线段,例如用v1替代线段l1,值为(x11-x10,y11-y10)。 *1.2.1:若不理解的话,就当是把原来的两条直线平移至经过坐标原点吧,因为平移不影响直线平等或垂直的关系 1.2.2:为方便书写与查看,设一些别名吧:v1=(X1,Y1),其中X1=x11-x10,Y1=y11-y10;v2=(X2,Y2),其中X2=x21-x20,Y2=y21-y20 1.3:向量垂直的条件是点积为0,所以这里判断垂直的条件是X1*X2 + Y1*Y2 == 0 1.4:平行的条件我想说得简单点,退回到直线就是它们与x轴的夹角相等,也就是斜率相等,所以条件是X1*Y2 == X2*Y1 2.1:与第1题一样的替代,距离等于该点到线段所在直线的距离,那关键就是在直线上找一个点,这个点与指定点的连成的直线与原来的直线垂直,最后要求的距离就是这两个点的距离了 2.2:同样,用向量替代题中的线段就是:v1=(X1,Y1),其中X1=x1-x0,Y1=y1-y0,然后凑一个与此向量垂直的向量v2出来,简单做法就是v2=(-Y1,X1), 代入点积公式必得0 2.2.1:当然v2也可以是(Y1,-X1),这里不妨用前一个,效果是一样的 *2.3:本题我对向量的理解是:从某点到另一点的增量,即二维的delta。借此就可以算出与题中线段垂直的直线上的另一个点,就是把前面算出的垂直向量加给点(x2,y2),就得到了(x2-Y1,y2+X1),即(x2-y1+y0,y2+x1-x0) 2.4:两点决定一直线,基于这两个点,我们就可以算出那条垂直直线的方程了,再加上题中线段的直线方程,那么这个关键点就是这两条直线的交点,问题转化为解二元一次方程组了。 2.5:最后距离就等于这个交点到(x2,y2)的距离 3.1:此题我的说法不太严谨,先这么简化:把扫描器的两条边看成两个向量v1=(X1,Y1),假定是左边那条;v2=(X2,Y2),假定是右边那条。从坐标原点到目标点看作向量v0(X0,Y0)。 3.2:那么目标点落在扫描器范围内的条件就是:v0在v1右边,同时也在v2的左边。(对于左边右边的说法我就先不给出严谨的说明了,不知道有没有专业术语) *3.3:重合的向量可以弱化理解为平行的向量,基于第一题的结论,假如v0与v1重合,就会有X0*Y1 == X1*Y0,即X0*Y1-X1*Y0 == 0, *3.3.1:那要是X0*Y1-X1*Y0的值不等于0呢?,那情况就是v0在v1的左边或右边了。 3.3.2:X0*Y1-X1*Y0这个式子是带方向性的,姑且定义为从v0旋转到v1,值有正负(反之X1*Y0-X0*Y1就是从v1旋转到v0) 3.4:那么把3.2的说法进一步数字化就是从v0旋转到v1与从v0旋转到v2互为相反数。(其实其中一个为0也行,表于目标点落在了边界上) 3.5:最后得出的公式化条件就是:(X0*Y1-X1*Y0) * (X0*Y2-X2*Y0) <= 0

    作者回复: 很棒~第二题不必求交点或者说垂足。可以直接用向量叉积的模等于平行四边形面积这一性质,再除以底边长度,得到的就是平行四边形的高,即点到直线的距离。

    2020-07-01
    4
  • Cailven
    那棵树让我想到了曾经用分形几何在webgl里玩生成艺术的经历。正所谓数学不好没法搞艺术,刚巧这句话就表现在图形学和视觉可视化所谓的创意编程这个范畴里。

    作者回复: 嗯嗯,后续课程中还会看到用分形思想绘制有趣图案

    2020-07-01
    4
  • weineel
    老师好,坐标系转换后怎么转换回来?

    作者回复: 乘上逆矩阵就可以转换回来

    2020-11-12
    2
  • 从此刻起开始
    这vector2d.js如何用?我在pycharm copy了老师上传的源码,但运行不了

    作者回复: 运行不了具体是指什么?这是ES Modules模块,较新的chrome浏览器中可以通过type=module的script标签加载,或者用babel编译。

    2020-09-29
    2
    1
  • SMW🙏🏻
    这个方法的逻辑没有看懂,大佬能否解释一下 rotate(rad) { const c = Math.cos(rad), s = Math.sin(rad); const [x, y] = this; this.x = x * c + y * -s; this.y = x * s + y * c; return this; } 我是这么实现的 rotate(rad) { const [x, y] = this const length = Math.hypot(x, y) const c = Math.cos(rad) const s = Math.sin(rad) this.x = length * c this.y = length * s return this }

    作者回复: rotate应该是旋转了rad角,不是旋转到。你实现的少了原来的角度。把正余弦用和角公式展开,就得到我的结果。

    2020-07-14
    2
    1
  • Geek_b6af14
    对坐标变换和图形平移的好处还是没太大感觉~~~

    作者回复: 可以等后续通过例子慢慢理解

    2020-07-13
    2
    1
  • 谭鹏
    画树的html文件 于兴起来没有内容 一个大白屏

    编辑回复: 收到,我们检查一下

    2021-05-15
    2
  • 番薯
    1.构建向量: a=(x11-x10,y11-y10) b=(x21-x20,y21-y20) 点积a•b=0余弦值为0则垂直 点积(a•b)²=(|a||b|)² 余弦值为±1则平行 2. 三点确定两条向量 a=(x1-x0,y1-y0) c=(x2-x0,y2-y0),勾股定理|a|²+|b|²=|c|² 可求得垂直边的长度 3.通过点(x,y)的正切值 可推出与y轴之间的角度

    作者回复: 可,不过有更简单的办法

    2021-02-06
收起评论
显示
设置
留言
32
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部