zoukankan      html  css  js  c++  java
  • 图形学 三次Hermite曲线绘制实现代码 javascript:es6+h5:canvas

    2019/11/20UPD:更正起点终点切矢量的取均值

    期末要考三次hermite曲线绘制编程题,熟悉一下,(虽然考的是opengl版本

      1 <!DOCTYPE html>
      2 <html lang="en">
      3 
      4 <head>
      5     <meta charset="UTF-8">
      6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
      7     <meta http-equiv="X-UA-Compatible" content="ie=edge">
      8     <link rel="stylesheet" type="text/css" href="2d.css">
      9     <script src="jquery.min.js"></script>
     10     <title>三次hermite曲线绘制</title>
     11     <style>
     12     </style>
     13 </head>
     14 
     15 <body>
     16     <canvas id="chart"></canvas>
     17     <script>
     18 
     19         class Point {
     20             constructor(x, y) {
     21                 this.x = Math.round(x) || 0;
     22                 this.y = Math.round(y) || 0;
     23             }
     24             set(x, y) {
     25                 this.x = Math.round(x) || 0;
     26                 this.y = Math.round(y) || 0;
     27             }
     28         }
     29         class Line {
     30             constructor(start, end) {
     31                 this.start = (start === undefined) ? new Point() : start;
     32                 this.end = (end === undefined) ? new Point() : end;
     33             }
     34             set(start, end) {
     35                 this.start = (start === undefined) ? new Point() : start;
     36                 this.end = (end === undefined) ? new Point() : end;
     37             }
     38         }
     39 
     40         let chart = document.getElementById("chart");
     41         let gridStep = 2;//网格大小,未画出
     42         let bigStep = 5;
     43         let gIsLButtonDown = false;
     44         let change = -1;//更改下标
     45         let p = new Array();//原始点
     46         let h = new Array();//基函数
     47         let pre_point = new Point();//拖动点
     48         const num = 1000;//每段直线画点个数
     49 
     50 
     51 
     52         function lpTodp(x) {
     53             return x * gridStep;
     54         }
     55 
     56         function dpTolp(x) {
     57             return Math.trunc(x / gridStep);
     58         }
     59 
     60         function drawPoint(ctx, x, y, color, step) {
     61             if (color)
     62                 ctx.fillStyle = color;
     63             if (!step)
     64                 step = gridStep;
     65             ctx.fillRect(lpTodp(x), lpTodp(y), step, step);
     66         }
     67 
     68         function drawLine(ctx, line) {//bresenham
     69             let dx, dy, upInc, downInc, x, y, d, isSwap = false;
     70             let tx, ty, e, dx2, dy2;
     71             let x1 = line.end.x, y1 = line.end.y;
     72             let x0 = line.start.x, y0 = line.start.y;
     73             dx = Math.abs(x1 - x0), dy = Math.abs(y1 - y0);
     74             if (dx < dy) {
     75                 [x0, y0] = [y0, x0];
     76                 [x1, y1] = [y1, x1];
     77                 [dx, dy] = [dy, dx];
     78                 isSwap = true;
     79             }
     80             tx = x0 <= x1 ? 1 : -1;
     81             ty = y0 <= y1 ? 1 : -1;
     82             e = -dx, x = x0, y = y0;
     83             dx2 = dx * 2, dy2 = dy * 2;
     84             while (x != x1) {
     85                 isSwap ? drawPoint(ctx, y, x) : drawPoint(ctx, x, y);
     86                 x += tx, e += dy2;
     87                 if (e > 0) {
     88                     y += ty;
     89                     e -= dx2;
     90                 }
     91             }
     92             isSwap ? drawPoint(ctx, y, x) : drawPoint(ctx, x, y);
     93         }
     94         function draw() {
     95             if (!chart.getContext) return;
     96             const ctx = chart.getContext("2d");
     97             //开始代码
     98             ctx.fillStyle = "rgb(255, 255, 255)";
     99             //绘制矩形
    100 
    101             const w = $("#chart").width();
    102             const h = $("#chart").height();
    103 
    104             ctx.fillRect(0, 0, w, h);
    105 
    106             for (let q of p)
    107                 drawPoint(ctx, q.x, q.y, "#ff0000", bigStep);
    108             ctx.fillStyle = "rgba(0, 0, 0,0.5)";
    109             drawHermite();
    110         }
    111 
    112 
    113         function getBaseFunction(t) {//基函数计算
    114             const t2 = t * t;
    115             const t3 = t2 * t;
    116             let cur = new Array(4);
    117             cur[0] = 2 * t3 - 3 * t2 + 1;
    118             cur[1] = -2 * t3 + 3 * t2;
    119             cur[2] = t3 - 2 * t2 + t;
    120             cur[3] = t3 - t2;
    121             return cur;
    122         }
    123 
    124         function drawHermite() {
    125             if (p.length < 4)
    126                 return;
    127             h = new Array();//置空
    128             const delta = 1.0 / num;
    129             const ctx = chart.getContext("2d");
    130             for (let i = 1; i < num; i++) {
    131                 const t = i * 1.0 / num;
    132                 h.push(getBaseFunction(t));
    133             }
    134             const m0 = new Point(p[1].x - p[0].x, p[1].y - p[0].y);
    135             const m1 = new Point(p[2].x - p[1].x, p[2].y - p[1].y);
    136             const m2 = new Point(p[3].x - p[2].x, p[3].y - p[2].y);
    137             const k0 = new Point((m0.x + m1.x) / 2, (m0.y + m1.y) / 2);//取均值作为切线
    138             const k1 = new Point((m1.x + m2.x) / 2, (m1.y + m2.y) / 2);
    139             drawLine(ctx, new Line(p[0], p[1]));
    140             let pre = undefined;
    141             for (let i = 0; i < num - 1; i++) {
    142                 const x = p[1].x * h[i][0] + p[2].x * h[i][1] + k0.x * h[i][2] + k1.x * h[i][3];
    143                 const y = p[1].y * h[i][0] + p[2].y * h[i][1] + k0.y * h[i][2] + k1.y * h[i][3];
    144                 const now = new Point(x, y);
    145                 if (pre)
    146                     drawLine(ctx, new Line(pre, now));
    147                 pre = now;
    148             }
    149             drawLine(ctx, new Line(pre, p[2]));
    150             drawLine(ctx, new Line(p[2], p[3]));
    151         }
    152 
    153         function getPoint(x, y) {//获取坐标
    154             const cur = new Point(x, y);
    155             if (change == -1) {//获取拖动坐标
    156                 for (let i = 0; i < p.length; i++)
    157                     if (p[i].x == cur.x && p[i].y == cur.y) {
    158                         pre_point = p[i];
    159                         change = i;
    160                     }
    161             }
    162             if (p.length == 4)
    163                 return;
    164             p.push(cur);
    165         }
    166         function movePoint(x, y, f) {
    167             if (change != -1)
    168                 pre_point.set(x, y);
    169             if (f)
    170                 change = -1;
    171         }
    172         function resizeCanvas() {
    173             // 将chart的大小设置为窗口大小, 但是为了避免偶尔溢出, 略微减去4个像素
    174             $('#chart').attr("width", $(window).get(0).innerWidth - 4);
    175             $('#chart').attr("height", $(window).get(0).innerHeight - 4);
    176             draw();
    177         };
    178 
    179         $(function () {
    180             $(window).resize(resizeCanvas);
    181             resizeCanvas();
    182 
    183             $('canvas').mousedown(function (e) {
    184                 var x = e.originalEvent.x || e.originalEvent.layerX || 0;
    185                 var y = e.originalEvent.y || e.originalEvent.layerY || 0;
    186                 x = dpTolp(x);
    187                 y = dpTolp(y);
    188                 gIsLButtonDown = true;
    189                 getPoint(x, y);
    190                 draw();
    191             });
    192 
    193             $('canvas').mousemove(function (e) {
    194                 if (gIsLButtonDown) {
    195                     let x = e.originalEvent.x || e.originalEvent.layerX || 0;
    196                     let y = e.originalEvent.y || e.originalEvent.layerY || 0;
    197                     x = dpTolp(x);
    198                     y = dpTolp(y);
    199                     movePoint(x, y);
    200                     draw();
    201                 }
    202             });
    203 
    204             $('canvas').mouseup(function (e) {
    205                 if (gIsLButtonDown) {
    206                     let x = e.originalEvent.x || e.originalEvent.layerX || 0;
    207                     let y = e.originalEvent.y || e.originalEvent.layerY || 0;
    208                     x = dpTolp(x);
    209                     y = dpTolp(y);
    210                     movePoint(x, y, 1);
    211                     draw();
    212                     gIsLButtonDown = false;
    213                 }
    214             });
    215         });
    216     </script>
    217 </body>
    218 
    219 </html>
    View Code

    实现效果(可拖拽端点)

  • 相关阅读:
    【C++】资源管理
    【Shell脚本】逐行处理文本文件
    【算法题】rand5()产生rand7()
    【Shell脚本】字符串处理
    Apple iOS产品硬件参数. 不及格的程序员
    与iPhone的差距! 不及格的程序员
    iPhone游戏 Mr.Karoshi"过劳死"通关. 不及格的程序员
    XCode V4 发布了, 苹果的却是个变态. 不及格的程序员
    何时readonly 字段不是 readonly 的?结果出呼你想象!!! 不及格的程序员
    object file format unrecognized, invalid, or unsuitable Command 不及格的程序员
  • 原文地址:https://www.cnblogs.com/mooleetzi/p/11886312.html
Copyright © 2011-2022 走看看