精华内容
下载资源
问答
  • 一个最最简单的例子:绘制一个从 0 到 360 度完整的 SIN 函数图形import numpy as npimport matplotlib.pyplot as ptx = np.arange(0, 360)# 如果打印 x ,NumPy 会给你很好看的打印格式# print(x)y = np.sin(x * np...

    一个最最简单的例子:

    绘制一个从 0 到 360 度完整的 SIN 函数图形

    import numpy as np

    import matplotlib.pyplot as pt

    x = np.arange(0, 360)

    # 如果打印 x ,NumPy 会给你很好看的打印格式

    # print(x)

    y = np.sin(x * np.pi / 180)

    pt.plot(x, y)

    pt.xlim(0, 360)

    pt.ylim(-1.2, 1.2)

    pt.title("SIN function")

    pt.show()

    下面我们加上一个 COS 函数图形,并且使用不同的颜色来表示。

    import numpy as np

    import matplotlib.pyplot as pt

    x = np.arange(0, 360)

    y = np.sin(x * np.pi / 180)

    z = np.cos(x * np.pi / 180)

    pt.plot(x, y, color='blue')

    pt.plot(x, z, color='red')

    pt.xlim(0, 360)

    pt.ylim(-1.2, 1.2)

    pt.title("SIN & COS function")

    pt.show()

    然后,我们加上图例,x 轴的说明和 y 轴的说明。

    import numpy as np

    import matplotlib.pyplot as pt

    x = np.arange(0, 360)

    print(x)

    y = np.sin(2 * x * np.pi / 180.0)

    z = np.cos(x * np.pi / 180.0)

    # 使用美元符号把标签包围起来,得到 LaTex 公式显示的效果

    pt.plot(x, y, color='blue', label="$SIN(2x)$")

    pt.plot(x, z, color='red', label="$COS(x)$")

    pt.xlim(0, 360)

    pt.ylim(-1.2, 1.2)

    pt.title("SIN & COS function")

    # 要有 pt.legend() 这个方法才会显示图例

    pt.legend()

    pt.show()

    以上这篇使用Matplotlib 绘制精美的数学图形例子就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

    展开全文
  • Astah绘制UML图形

    2019-05-23 11:49:08
    Astah绘制UML图形-入门篇这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个...


    Astah绘制UML图形-入门篇这里写自定义目录标题)

    欢迎使用Markdown编辑器

    你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

    新的改变

    我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

    1. 全新的界面设计 ,将会带来全新的写作体验;
    2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
    3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
    4. 全新的 KaTeX数学公式 语法;
    5. 增加了支持甘特图的mermaid语法1 功能;
    6. 增加了 多屏幕编辑 Markdown文章功能;
    7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
    8. 增加了 检查列表 功能。

    功能快捷键

    撤销:Ctrl/Command + Z
    重做:Ctrl/Command + Y
    加粗:Ctrl/Command + B
    斜体:Ctrl/Command + I
    标题:Ctrl/Command + Shift + H
    无序列表:Ctrl/Command + Shift + U
    有序列表:Ctrl/Command + Shift + O
    检查列表:Ctrl/Command + Shift + C
    插入代码:Ctrl/Command + Shift + K
    插入链接:Ctrl/Command + Shift + L
    插入图片:Ctrl/Command + Shift + G

    合理的创建标题,有助于目录的生成

    直接输入1次#,并按下space后,将生成1级标题。
    输入2次#,并按下space后,将生成2级标题。
    以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

    如何改变文本的样式

    强调文本 强调文本

    加粗文本 加粗文本

    标记文本

    删除文本

    引用文本

    H2O is是液体。

    210 运算结果是 1024.

    插入链接与图片

    链接: link.

    图片: Alt

    带尺寸的图片: Alt

    居中的图片: Alt

    居中并且带尺寸的图片: Alt

    当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

    如何插入一段漂亮的代码片

    博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

    // An highlighted block
    var foo = 'bar';
    

    生成一个适合你的列表

    • 项目
      • 项目
        • 项目
    1. 项目1
    2. 项目2
    3. 项目3
    • 计划任务
    • 完成任务

    创建一个表格

    一个简单的表格是这么创建的:

    项目 Value
    电脑 $1600
    手机 $12
    导管 $1

    设定内容居中、居左、居右

    使用:---------:居中
    使用:----------居左
    使用----------:居右

    第一列 第二列 第三列
    第一列文本居中 第二列文本居右 第三列文本居左

    SmartyPants

    SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

    TYPE ASCII HTML
    Single backticks 'Isn't this fun?' ‘Isn’t this fun?’
    Quotes "Isn't this fun?" “Isn’t this fun?”
    Dashes -- is en-dash, --- is em-dash – is en-dash, — is em-dash

    创建一个自定义列表

    Markdown
    Text-to-HTML conversion tool
    Authors
    John
    Luke

    如何创建一个注脚

    一个具有注脚的文本。2

    注释也是必不可少的

    Markdown将文本转换为 HTML

    KaTeX数学公式

    您可以使用渲染LaTeX数学表达式 KaTeX:

    Gamma公式展示 Γ(n)=(n1)!nN\Gamma(n) = (n-1)!\quad\forall n\in\mathbb N 是通过欧拉积分

    Γ(z)=0tz1etdt . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.

    你可以找到更多关于的信息 LaTeX 数学表达式here.

    新的甘特图功能,丰富你的文章

    Mon 06Mon 13Mon 20已完成 进行中 计划一 计划二 现有任务Adding GANTT diagram functionality to mermaid
    • 关于 甘特图 语法,参考 这儿,

    UML 图表

    可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

    张三李四王五你好!李四, 最近怎么样?你最近怎么样,王五?我很好,谢谢!我很好,谢谢!李四想了很长时间,文字太长了不适合放在一行.打量着王五...很好... 王五, 你怎么样?张三李四王五

    这将产生一个流程图。:

    链接
    长方形
    圆角长方形
    菱形
    • 关于 Mermaid 语法,参考 这儿,

    FLowchart流程图

    我们依旧会支持flowchart的流程图:

    Created with Raphaël 2.2.0开始我的操作确认?结束yesno
    • 关于 Flowchart流程图 语法,参考 这儿.

    导出与导入

    导出

    如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

    导入

    如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
    继续你的创作。


    1. mermaid语法说明 ↩︎

    2. 注脚的解释 ↩︎

    展开全文
  • Matlab文本的Interpreter属性使我们能在图形中显示一个较为复杂的公式,例如在公式中除了有希腊字母外,还有分号、根号等数学符号。当键入:>> set(text,'Interpreter')Matlab将返回'Interpreter'所包含的属性...

    Matlab文本的Interpreter属性使我们能在图形中显示一个较为复杂的公式,例如在公式中除了有希腊字母外,还有分号、根号等数学符号。

    当键入:>> set(text,'Interpreter')

    Matlab将返回'Interpreter'所包含的属性值:

    [ latex | {tex} | none ]。

    默认值是tex。

    Tex的用法在Matlab的帮助文档里有详细介绍,这里主要介绍一下如何采用latex编辑公式。

    在matlab中,Latex编辑公式的基本格式:

    ( 数学公式 ),或者$ 数学公式 $,或者$$ 数学公式 $$。

    具体的公式编辑命令:

    1.上标用^和下表用_,希腊字母与tex一样,即alpha表示α。

    2.求和

    $$sum_{i=1}^{n} x_{i}$$

    3.积分

    $$ int_{0}^{1}$$

    4.求极限

    $$lim_{n rightarrow infty}$$ %n趋于无穷符号在lim正下方

    $lim_{n rightarrow infty} $ %趋于无穷符号在lim右下角

    5. 分式

    $$frac{1}x$$ %1/x

    6. 根式

    $$sqrt{x}$$

    7. 上划线

    $$overline{x}$$

    8. 下划线

    $$underline{x}$$ %下划线在x的正下方

    9.卧式花括号命令

    $$overbrace{x+y+z+w}$$

    10.仰式花括号命令

    $$a+underbrace{b+c+d} $$

    11.戴帽命令

    $$hat{o} check{o} breve{o}$$

    $$widehat{A+B} widetilde{a+b}$$

    $$vec{imath}+vec{jmath}=vec{k}$$

    12.堆砌命令

    $$ystackrel{rm def}{=} f(x) stackrel{xrightarrow

    0}{rightarrow} A$$

    13.省略号

    $cdots ldots vdots ddots $

    例:

    h = text;

    set(h,'Interpreter','latex');

    set(h,'string','$$sum_{i=1}^{n}

    x_{i}=int_{0}^{1}f(x)dx$$','position',[0.1,0.5],'FontSize',16);

    展开全文
  • 在canvas上绘制3d图形

    2020-06-26 10:29:44
    文章里有相当多的用到中学数学中的知识,推导3d的几何模型是如何绘制到2d平面中去的,最终利用推导出的结论编写代码,实现一个波纹的demo 项目地址:https://github.com/zz632893783/canvas-3d 安装项目依赖...

    项目简介

    文章里有相当多的用到中学数学中的知识,推导3d的几何模型是如何绘制到2d平面中去的,最终利用推导出的结论编写代码,实现一个波纹的demo

    转载自:https://www.jianshu.com/p/e3ebe08dddad
    项目地址:https://github.com/zz632893783/canvas-3d

     

    安装项目依赖模块

    npm install
    

    运行项目

    npm run dev
    

    从z轴观察yz平面上的点

     

    想象一下有这么一个三维空间(如图),有一个点B,我们从A点观察B点。那么B点在xy平面上的投影即AB的延长线与平面xy的交点C。而xy平面不就是可以看一个二维的canvas画布吗。
    我们暂且将A点放在z轴,B点放在yz平面,则A点的三维坐标可以表示为
    A(0,0,zA),B点的三维坐标可以表示为B(0,yB,zB)。从B点做一条垂线垂z轴于D点。
    ADB与AOC是相似三角形,所以有

     

    变换得


    其中DB即B点的y坐标,AO即A点的z坐标,DO即B点的z坐标,所以

     

    这里的OC也就是C点的y坐标。

    从z轴观察xz平面上的点

     

    同理我们从A点观察平面xz上的某一点E(xE,0,zE),ADE与AOF是相似三角形

     

    变换得

     

    从z轴观察空间内任意坐标

    之前所观测的B点是位于yz平面内,E点是位于xz平面内,但是如果是空间内任意位置的点呢
    其实道理都是一样的,如下如

     

     

    如果将直线BD平移到E点,直线DE平移到B点,那么将形成一个矩形DBGE,矩形DBGE在xy平面上的投影为矩形OCHF。
    由于AGE与AHF相似,所以有


    并且由于ADE与AOF也是相似三角形,所以

     

    所以

     

    推导得

     


    其中GE也就是G点的y坐标,因为矩形DBGE是平行于xy平面的,所以它们z坐标相同,DO等价于G点的z坐标,所以对于空间内任意位置G(xG,yG,zG)

     


    同样的方法我们可以推导出

     

    变换得

     

    结合上两步,CH是H点的x坐标,HF是H点的y坐标,所以从轴上的点A(0,0,zA)观察空间内任意位置G(xG,yG,zG)在平面xy上的投影可表示为

     

    从任意位置观察空间内任意坐标

    沿着x轴平移坐标系

    之前的推论到从z轴观察空间内任意位置的投影了,但是实际上A点是有特殊性的,因为它是位于z轴上的某一个点,其xy坐标都为0,如果A是空间内的任意一个点,情况又如何,请看下图

     

    假设这个时候真正的坐标系是xy'z',而坐标系xyz是我们临时所建立的一个虚拟的坐标系,那么这个时候A点相对于坐标系xy'z'来说,坐标点可表示为A(xA,0,zA),G点依旧表示为(xG,yG,zG)
    我们之前推导的相似三角形的关系,即使换了坐标系,它们的关系依然成立,所以

     

    变换得


    只不过这个时候 BG=xG-xA,AO与DO与之前相同
    求得


    之前推导出的相似三角形关系依旧成立,所以

     

    变换得


    由于GE,AO,DO与之前相比都没有变化,
    所以得


    与之前的推导一致,最后我们得出结论,我们沿着x轴方向移动坐标系的时候(即图中的坐标系有xy'z'移动到了xyz位置),G点在平面xy的投影H点的y坐标不会有变化,但是x坐标为

     

    沿着y轴平移坐标系

    如下图

     

    假设x'yz'是真正的坐标系,沿着y轴平移得到临时坐标系xyz,推导步骤和之前的相同,这里不再赘述,直接贴结果

     


    也就是说当沿着y轴方向移动坐标系的时候,投影H的x坐标不会有变化,y坐标变为

     

    对于空间内任意位置

    对于空间内任意位置,我们都可以看成是在z轴上的某一点A(0,0,zA),先经历一次x轴方向的平移(此时投影H的y坐标不变),再经历一次y轴方向的平移(此时投影H的x坐标不变),平移之前点A观察到点G的投影H坐标可表示为

     

    对其进行x轴方向的平移,(此时投影H的y坐标不变),H的坐标可表示为


    再对其进行y轴方向的平移,(此时投影H的x坐标不变),H的坐标可表示为

     

    最终结论

    从空间内的任意点A(xA,yA,zA)观察空间内的任一点G(xG,yG,zG),它在xy平面内的投影H的坐标为

     

    首先我们尝试写一个简单的几何图形


    立方体边长为100,则A(-50,50,50),B(-50,50,-50),C(50,50,-50),D(50,50,50),E(-50,-50,50),F(-50,-50,-50),G(50,-50,-50),H(50,-50,50),假定从z轴上某一点(0,0,300)观察

    <template>
        <div class="cube">
            <canvas ref="cube" v-bind:width="canvasWidth" v-bind:height="canvasHeight"></canvas>
        </div>
    </template>
    <script>
    export default {
        data: function () {
            return {
                canvasWidth: 600,
                canvasHeight: 400,
                ctx: null,
                visual: {
                    x: 0,
                    y: 0,
                    z: 300
                },
                pointMap: {
                    A: (-50, 50, 50),
                    B: (-50, 50, -50),
                    C: (50, 50, -50),
                    D: (50, 50, 50),
                    E: (-50, -50, 50),
                    F: (-50, -50, -50),
                    G: (50, -50, -50),
                    H: (50, -50, 50)
                }
            }
        },
        methods: {
            init: function () {
                this.ctx = this.$refs.cube.getContext('2d')
            },
            draw: function () {}
        },
        mounted: function () {
            this.init()
            this.draw()
        }
    }
    </script>
    

    绘制方法也很简单,分别绘制矩形ABCD,矩形EFGH,然后再将AE,BF,CG,DH连线即可,只不过这里的ABCDEFGH点需要换算成投影在三维坐标系xy平面上的点,运用我们之前得出的结论,我们定义一个转换坐标点的函数

            transformCoordinatePoint: function (x, y, z, offsetX = this.canvasWidth / 2, offsetY = this.canvasHeight / 2) {
                return {
                    x: (x - this.visual.x) * this.visual.z / (this.visual.z - z) + offsetX,
                    y: (y - this.visual.y) * this.visual.z / (this.visual.z - z) + offsetY
                }
            }
    

    然后编写draw函数

            draw: function () {
                let point
                this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
                // 绘制矩形ABCD
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.A)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.B)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.C)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.D)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.closePath()
                this.ctx.stroke()
                // 绘制矩形EFGH
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.E)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.F)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.G)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.H)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.closePath()
                this.ctx.stroke()
                // 绘制直线AE
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.A)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.E)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
                // 绘制直线BF
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.B)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.F)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
                // 绘制直线CD
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.C)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.G)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
                // 绘制直线DH
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.D)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.H)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
            }
    

    查看代码运行结果


    似乎是对的,但是有感觉怪怪的,我们尝试将立方体绕着y轴旋转
    这里需要另一个数学关系的推导


    想象一下从y轴俯视yz平面,这个时候点D的位置关系如下图


    这个时候假定D点与x轴的夹角是α,圆的半径为R,将D点绕着y轴旋转β旋转至D'点,这个时候D'与x轴夹角为α+β,此时D'的x坐标为cos(α+β)R,D'的z坐标为sin(α+β)R
    回一下中学时候我们学过的三角形倍角公式

     


    D'的x坐标cos(α+β)R=Rcosαcosβ-Rsinαsinβ
    D'的z坐标sin(α+β)
    R=Rsinαcosβ+Rcosαsinβ
    而Rsinα就是旋转之前D点的z坐标,Rcosα就是旋转之前D点的x坐标,
    D'的x坐标为xcosβ-zsinβ
    D'的z坐标为zcosβ+xsinβ
    将结论代入到我们的立方体的8个顶点ABCDEFGH中
    对于任一点D(xD,yD,zD),其绕y轴旋转β角的时候,它的三维坐标变为(xDcosβ-zDsinβ,yD,zDcosβ+xDsinβ)
    转换为代码

        methods: {
            init: function () {
                this.ctx = this.$refs.cube.getContext('2d')
            },
            transformCoordinatePoint: function (x, y, z, offsetX = this.canvasWidth / 2, offsetY = this.canvasHeight / 2) {
                return {
                    x: (x - this.visual.x) * this.visual.z / (this.visual.z - z) + offsetX,
                    y: (y - this.visual.y) * this.visual.z / (this.visual.z - z) + offsetY
                }
            },
            draw: function () {
                let point
                this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
                // 绘制矩形ABCD
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.A)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.B)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.C)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.D)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.closePath()
                this.ctx.stroke()
                // 绘制矩形EFGH
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.E)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.F)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.G)
                this.ctx.lineTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.H)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.closePath()
                this.ctx.stroke()
                // 绘制直线AE
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.A)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.E)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
                // 绘制直线BF
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.B)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.F)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
                // 绘制直线CD
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.C)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.G)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
                // 绘制直线DH
                this.ctx.beginPath()
                point = this.transformCoordinatePoint(...this.pointMap.D)
                this.ctx.moveTo(point.x, point.y)
                point = this.transformCoordinatePoint(...this.pointMap.H)
                this.ctx.lineTo(point.x, point.y)
                this.ctx.stroke()
                this.ctx.closePath()
            },
            animationFrame: function () {
                let rotationAngle = 1
                window.requestAnimationFrame(() => {
                    for (let key in this.pointMap) {
                        let point = this.pointMap[key]
                        // 保存x,y,z坐标
                        let x = point[0]
                        let y = point[1]
                        let z = point[2]
                        // 变换后的x坐标
                        point[0] = x * Math.cos(rotationAngle / 180 * Math.PI) - z * Math.sin(rotationAngle / 180 * Math.PI)
                        // 绕y轴旋转,y左边不会发生变化
                        point[1] = y
                        // 变换后的z坐标
                        point[2] = z * Math.cos(rotationAngle / 180 * Math.PI) + x * Math.sin(rotationAngle / 180 * Math.PI)
                    }
                    this.draw()
                    this.animationFrame()
                })
            }
        },
        mounted: function () {
            this.init()
            this.animationFrame()
        }
    

    代码运行效果

     

    绘制波浪

    波浪是由若干条正弦函数组成的,我们先绘制一条正弦函数
    中学数学中,描述一条正弦函数的方程式 y=a*sin(b * x + c) + d,所以我们构造一个类,需要的参数也是a,b,c,d,为了确定函数的起始位置和结束位置,另外需要两个参数start,end

    class Line {
        constructor (a, b, c, d, start, end) {
            this.a = a
            this.b = b
            this.c = c
            this.d = d
            this.start = start
            this.end = end
        }
    }
    export default Line
    

    实际上每条正弦函数曲线并不是真正的连线,而是由于一个个点组成,我们在增加一个参数,确定每个点之间的间距,并在实例化的时候生成这些点,我们这里保存在pointList中

    class Line {
        constructor (a, b, c, d, start, end, gap) {
            this.a = a
            this.b = b
            this.c = c
            this.d = d
            this.start = start
            this.end = end
            this.gap = gap
            this.pointList = []
            this.computePointList()
        }
        computePointList () {
            this.pointList = []
            for (let i = this.start; i <= this.end; i = i + this.gap) {
                let x = i
                let y = this.a * Math.sin((this.b * x + this.c) / 180 * Math.PI) + this.d
                this.pointList.push({
                    x,
                    y
                })
            }
        }
    }
    export default Line
    

    在页面中,Line实例保存在lineList中,遍历lineList绘制点

    <template>
        <canvas class="wave" ref="wave" v-bind:width="canvasWidth" v-bind:height="canvasHeight"></canvas>
    </template>
    <script>
    import Line from './line'
    export default {
        props: {},
        data: function () {
            return {
                canvasWidth: 600,
                canvasHeight: 400,
                ctx: null,
                visual: {
                    x: 0,
                    y: -100,
                    z: 1000
                },
                lineList: [
                    new Line(20, 2, 0, 0, -200, 200, 10)
                ]
            }
        },
        methods: {
            init: function () {
                this.ctx = this.$refs.wave.getContext('2d')
            },
            draw: function () {
                this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
                this.lineList.forEach(line => {
                    line.pointList.forEach(item => {
                        this.ctx.beginPath()
                        this.ctx.arc(item.x + this.canvasWidth / 2, item.y + this.canvasHeight / 2, 2, 0, 2 * Math.PI)
                        this.ctx.closePath()
                        this.ctx.fill()
                    })
                })
            }
        },
        mounted: function () {
            this.init()
            this.draw()
        }
    }
    </script>
    <style lang="stylus" scoped>
        .wave {
            border: 1px solid;
        }
    </style>
    

    看一下代码效果

     

    我们再试着让它动起来,波浪的运动改变的实际上是每个点的纵坐标,只要我们知道每个点距离原点的偏移量,我们就能计算出当前的纵坐标,所以我们在生成点的时候,记录偏移量,我们我们声明一个updatePointList方法用以跟新点的位置

        computePointList () {
            this.pointList = []
            for (let i = this.start; i <= this.end; i = i + this.gap) {
                let x = i
                let y = this.a * Math.sin((this.b * x + this.c) / 180 * Math.PI) + this.d
                let offset = i
                this.pointList.push({
                    x,
                    y,
                    offset
                })
            }
        }
        updatePointList () {
            this.pointList.forEach(item => {
                item.y = this.a * Math.sin((this.b * item.x + this.c + item.offset) / 180 * Math.PI) + this.d
            })
        }
    

    在页面中,我们定义一个变量lineOffset,通过调整它控制line实例的c值(也就是对直线进行平移),并不断地调用之前写好的updatePointList方法,更新点的位置

            animationFrame: function () {
                window.requestAnimationFrame(() => {
                    this.lineList.forEach(line => {
                        line.c = this.lineOffset
                        line.updatePointList()
                    })
                    this.lineOffset = this.lineOffset + 1
                    this.draw()
                    this.animationFrame()
                })
            }
    

    代码运行效果

     

    但是这个只是二维平面的,想象一下空间中有很多条这样的直线,然后有的直线离屏幕比较近,有的离屏幕比较远,所以我们如果在三维空间中描述直线的话,我们还需要知道三维坐标系中的z坐标,除此之代直线的x,z与之前的相比并无变化

        constructor (a, b, c, d, z, start, end, gap) {
            this.a = a
            this.b = b
            this.c = c
            this.d = d
            this.z = z
            this.start = start
            this.end = end
            this.gap = gap
            this.pointList = []
            this.computePointList()
        }
    

    我们之前已经推导过,对于任一点D(xD,yD,zD),其绕y轴旋转β角的时候,它的三维坐标变为(xDcosβ-zDsinβ,yD,zDcosβ+xDsinβ),想象一下我们直线上的每一个点,其实都是绕着y轴旋转的,旋转之后y轴的坐标不会发生变化,然后看我们原型中声明的updatePointList方法

        updatePointList () {
            this.pointList.forEach(item => {
                item.y = this.a * Math.sin((this.b * item.x + this.c + item.offset) / 180 * Math.PI) + this.d
            })
        }
    

    y轴的坐标我们之前已经写好了,我们运用(xDcosβ-zDsinβ,yD,zDcosβ+xDsinβ)推导每个点旋转β角后的坐标位置

        updatePointList (rotationAngleSpeed) {
            this.pointList.forEach(item => {
                let x = item.x
                let z = item.z
                item.x = x * Math.cos(rotationAngleSpeed / 180 * Math.PI) - z * Math.sin(rotationAngleSpeed / 180 * Math.PI)
                item.z = z * Math.cos(rotationAngleSpeed / 180 * Math.PI) + x * Math.sin(rotationAngleSpeed / 180 * Math.PI)
            })
        }
    

    代码运行效果

     

    但是此时的粒子并没有沿着y轴方向移动,我们将两步结合

        updatePointList (rotationAngleSpeed, visual) {
            this.pointList.forEach(item => {
                let x = item.x
                let y = item.y
                let z = item.z
                item.x = x * Math.cos(rotationAngleSpeed / 180 * Math.PI) - z * Math.sin(rotationAngleSpeed / 180 * Math.PI)
                item.z = z * Math.cos(rotationAngleSpeed / 180 * Math.PI) + x * Math.sin(rotationAngleSpeed / 180 * Math.PI)
                item.y = this.a * Math.sin((this.b * x + this.c + item.offset) / 180 * Math.PI) + this.d
            })
        }
    

    然后我们看一下运行结果

     

    非常的怪异,我们似乎哪里写错了
    回过头来看我们的代码,波纹的左右移动实际上是靠从新计算每个点的y坐标实现,而计算y坐标我们用的函数是

    item.y = this.a * Math.sin((this.b * x + this.c + item.offset) / 180 * Math.PI) + this.d
    

    但是我们实际上每计算一次item.y的值,我们通过控制this.c来实现平移,所以除了this.c之外,

    this.a * Math.sin((this.b * x + this.c + item.offset) / 180 * Math.PI) + this.d
    

    中的 this.a,x(这里的x也就是item.x),this.b,item.offset,this.d都不应该有变化,但是我们代码中的

    item.x = x * Math.cos(rotationAngleSpeed / 180 * Math.PI) - z * Math.sin(rotationAngleSpeed / 180 * Math.PI)
    

    却在不停地变化item.x的值,所以我们需要保存一份最开始时时候的x值

        computePointList () {
            this.pointList = []
            for (let i = this.start; i <= this.end; i = i + this.gap) {
                let x = i
                let y = this.a * Math.sin((this.b * x + this.c) / 180 * Math.PI) + this.d
                let offset = i
                this.pointList.push({
                    x,
                    y,
                    z: this.z,
                    originX: x,
                    offset
                })
            }
        }
        updatePointList (rotationAngleSpeed, visual) {
            this.pointList.forEach(item => {
                let x = item.x
                let y = item.y
                let z = item.z
                item.x = x * Math.cos(rotationAngleSpeed / 180 * Math.PI) - z * Math.sin(rotationAngleSpeed / 180 * Math.PI)
                item.z = z * Math.cos(rotationAngleSpeed / 180 * Math.PI) + x * Math.sin(rotationAngleSpeed / 180 * Math.PI)
                item.y = this.a * Math.sin((this.b * item.originX + this.c + item.offset) / 180 * Math.PI) + this.d
            })
        }
    

    继续看运行效果

     

    虽然代码是对的,但是这个时候的这些点还只是平面上的点,并没有3d效果,我们回到最开始推导出的结论
    从空间内的任意点A(xA,yA,zA)观察空间内的任一点G(xG,yG,zG),它在xy平面内的投影H的坐标为


    我们顶一个个观察点

        visual: {
            x: 0,
            y: -100,
            z: 1000
        }
    

    并在每次updatePointList方法中调用它,计算这个点在平面xy上的投影位置

            animationFrame: function () {
                window.requestAnimationFrame(() => {
                    this.lineList.forEach(line => {
                        line.c = this.lineOffset
                        line.updatePointList(this.rotationAngleSpeed, this.visual)
                    })
                    this.lineOffset = this.lineOffset + 1
                    this.draw()
                    this.animationFrame()
                })
            }
    

    在updatePointList函数中,我们拿到传入的视角点visual,并根据视角点计算空间内的点在平面xy上的投影,我们记为(canvasX,canvasY)

        updatePointList (rotationAngleSpeed, visual) {
            this.pointList.forEach(item => {
                let x = item.x
                let y = item.y
                let z = item.z
                item.x = x * Math.cos(rotationAngleSpeed / 180 * Math.PI) - z * Math.sin(rotationAngleSpeed / 180 * Math.PI)
                item.z = z * Math.cos(rotationAngleSpeed / 180 * Math.PI) + x * Math.sin(rotationAngleSpeed / 180 * Math.PI)
                item.y = this.a * Math.sin((this.b * item.originX + this.c + item.offset) / 180 * Math.PI) + this.d
                item.canvasX = (item.x - visual.x) * visual.z / (visual.z - z)
                item.canvasY = (item.y - visual.y) * visual.z / (visual.z - z)
            })
        }
    

    由于我们现在是要绘制投影的坐标,所以我们的draw方法中的绘制圆点的方法需要换成(canvasX,canvasY)

            draw: function () {
                this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
                this.lineList.forEach(line => {
                    line.pointList.forEach(item => {
                        this.ctx.beginPath()
                        this.ctx.arc(item.canvasX + this.canvasWidth / 2, item.canvasY + this.canvasHeight / 2, 2, 0, 2 * Math.PI)
                        this.ctx.closePath()
                        this.ctx.fill()
                    })
                })
            }
    

    运行结果

     

    然后我们试着加入更多的线条

                lineList: [
                    new Line(20, 2, 0, 0, -150, -200, 200, 10),
                    new Line(20, 2, 0, 0, -120, -200, 200, 10),
                    new Line(20, 2, 0, 0, -90, -200, 200, 10),
                    new Line(20, 2, 0, 0, -60, -200, 200, 10),
                    new Line(20, 2, 0, 0, -30, -200, 200, 10),
                    new Line(20, 2, 0, 0, 0, -200, 200, 10),
                    new Line(20, 2, 0, 0, 30, -200, 200, 10),
                    new Line(20, 2, 0, 0, 60, -200, 200, 10),
                    new Line(20, 2, 0, 0, 90, -200, 200, 10),
                    new Line(20, 2, 0, 0, 120, -200, 200, 10),
                    new Line(20, 2, 0, 0, 150, -200, 200, 10)
                ]
    

    运行结果

     

    我们试着再对每条直线作不同的平移,我们平移直线是通过line构造函数中的参数c控制的,在animationFrame方法中

            animationFrame: function () {
                window.requestAnimationFrame(() => {
                    this.lineList.forEach((line, index) => {
                        line.c = this.lineOffset
                        line.updatePointList(this.rotationAngleSpeed, this.visual)
                    })
                    this.lineOffset = this.lineOffset + 1
                    this.draw()
                    this.animationFrame()
                })
            }
    

    line.c是被赋值为this.lineOffset,所以我们看到每条直线的偏移量都是一致的,我们试着修改代码,使每条直线的偏移量不一致

            animationFrame: function () {
                window.requestAnimationFrame(() => {
                    this.lineList.forEach((line, index) => {
                        line.c = this.lineOffset + index * 30
                        line.updatePointList(this.rotationAngleSpeed, this.visual)
                    })
                    this.lineOffset = this.lineOffset + 1
                    this.draw()
                    this.animationFrame()
                })
            }
    

    代码运行结果

     

    实际上我们还忽略了一个点,那就是点的远近大小关系,真实情况应该是离我们屏幕较近的点,看起来更大,离屏更远的点,看起来更小,而离屏幕的距离不就是z的坐标吗
    我们回到最开始推论的那副图


    在A点观察直线DB在平面xy内的投影OC,由相似三角形可知

     

    推导得


    所以假定小圆点的半斤是R,站在A(0,0,)点观测小圆点位于平面xy上投影的半径为


    我们将draw方法中的代码做修改

            draw: function () {
                this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
                this.lineList.forEach(line => {
                    line.pointList.forEach(item => {
                        this.ctx.beginPath()
                        // 暂且假定小圆点的原始半径是2,则投影半径可表示为
                        let pointSize = 2 * this.visual.z / (this.visual.z - item.z)
                        this.ctx.arc(item.canvasX + this.canvasWidth / 2, item.canvasY + this.canvasHeight / 2, pointSize, 0, 2 * Math.PI)
                        this.ctx.closePath()
                        this.ctx.fill()
                    })
                })
            }
    

    运行效果

     

    我们不断调整实例化时候line的各个参数,最终实现效果


    到此,请记住这篇文章最重要的一个结论
    从空间内的任意点A(xA,yA,zA)观察空间内的任一点G(xG,yG,zG),它在xy平面内的投影H的坐标为

     

    如果以后还有与canvas绘制3d图形有关的文章,这个结论会一直用到

     

    展开全文
  • OpenGL 绘制几何图形

    千次阅读 2010-03-17 10:51:00
    另一方面,无论图形输出设备(例如,显示器)如何精确,始终不能输出一个无穷小的点。一般情况下,OpenGL中的点将被画成单个的像素(像素的概念,请自己搜索之~),虽然它可能足够小,但并不会是无
  • html5画布拖动绘制图形 在浏览器中绘制图形曲线从未如此简单。 直到最近,如果需要平滑的图表,则必须在服务器上生成图像或创建SVG。 动态创建曲线需要忍者JavaScript技能,数学学位和极大的耐心。 canvas元素已...
  • 本节书摘来自华章计算机...前面了解了基本图形的绘制方法,下面我们来看看复杂图形如何绘制。2.2.1 画曲线贝塞尔曲线,又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。在这里我们不研...
  • canvas绘制图形入门

    2018-12-30 12:33:17
    canvas绘制topo图欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...
  • 本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念。 一、点、直线和多边形 我们知道数学(具体的说,是几何学)中有点、直线和多边形的概念,但这些概念在计算机中会有所不同。...
  • 本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念。 一、点、直线和多边形我们知道数学(具体的说,是几何学)中有点、直线和多边形的概念,但这些概念在计算机中会有所不同。数学上的...
  • 第二课,绘制几何图形

    千次阅读 2008-01-21 13:32:00
    原帖地址:http://www.programfan.com/club/showbbs.asp?id=184525本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念。一、点、直线和多边形我们知道数学(具体的说,是几何学)中有点、...
  • 一、点、直线和多边形 ...另一方面,无论图形输出设备(例如,显示器)如何精确,始终不能输出一个无穷小的点。一般情况下,OpenGL中的点将被画成单个的像素(像素的概念,请自己搜索之~),虽然它可能足够小,但并
  • openlayers--绘制图形

    2020-12-16 14:32:05
    有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学...
  • 在前面我们讲过了如何初始化D3D11Device设备初始化等等,这里所讲的绘制图形将在上一篇文章的项目里进行扩展,在屏幕中绘制图形。在3D的呈现中最小的单位为三角形,无论我们看到的是多么大或多么小的,都是有一个或...
  • 我应该通过python读取这些数据,从而使用matplotlib生成一个3D图形。我看过很多pyton代码,但我不知道如何从数据中找出x、y和z轴。我知道这是一个模糊而蹩脚的问题,但我不熟悉这个问题,数学也很差。在在数据.txt在...
  • PYTHON基本图形绘制

    2020-03-25 13:38:39
    程序设计入门编写程序设计语法元素入门编写模板生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的...
  • 另一方面,无论图形输出设备如何精确,  始终不能输出一个无穷小的点。一般情况下,OpenGL中的点将被画成单个的像素,虽然它可能足够小,但并不会是无穷小。  同一像素上,OpenGL可以绘制许多坐标只有稍微不同的...
  • 大数据文摘作品,转载具体要求见文末编译团队:Aileen,徐凌霄用Python绘制著名的数学图片或动画,展示数学中的算法魅力。本项⽬目将持续更更新,数学中有着太多有趣的事物可以⽤用代码去展示。 欢迎提出建议和参与...
  • 中学数学中会接触到立体几何,它是很抽象的一个部份,学生们对于立体图形很难凭想象去理解,所以在讲课时可以利用几何画板课件制作工具绘制立体图形进行展示,本文就向大家介绍具体绘制技巧。 几何画板软件获取地址...
  • 看见函数app是一个专业的函数绘制工具,函数是数学中非常重要的内容,许多同学会觉得手动化函数太麻烦,那么你就非常需要这款手机应用,它支持加、减、乘、除、幂函数、指数函数、对数函数、三角函数,反三角函数等...
  • 本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念。 一、点、直线和多边形 我们知道数学(具体的说,是几何学)中有点、直线和多边形的概念,但这些概念在计算机中会有所不同。 ...
  • 本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念。一、点、直线和多边形我们知道数学(具体的说,是几何学)中有点、直线和多边形的概念,但这些概念在计算机中会有所不同。数学上的点...
  • 一、打开visio,在图表和数学图形中选择三角形,然后将其拖拽到画布。 二、鼠标左键选中生成的三角形,然后点击左下角的宽或高,编辑图形数据。 三、输入符合等边三角形的数据即可。 ...
  • 几何画板作为数学老师必备的课件制作工具,可以画出任意几何图形,下面就介绍用几何画板画菱形的方法。 几何画板软件开学特惠,软件获取地址:http://wm.makeding.com/iclk/?zoneid=17783 绘制菱形的步骤如下: (1...
  • 作为数学老师必备的课件制作工具,几何画板给老师的教学带来了方便,不仅可以画几何图形,还能画函数图像。其有别于其它的几何绘图工具,研究函数图象时少不了函数的切线,怎样用几何画板画函数切线呢? 几何画板...
  • 多媒体教学环境下,需要老师们掌握教学辅助工具,比如几何画板这款课件制作工具,它作为一个强大的几何绘图工具,能够绘制许多几何图形,当然也包括直角三角形了。下面就一起来学习用几何画板画直角三角形。 目前该...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 242
精华内容 96
关键字:

如何绘制数学图形