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

    实现效果(可拖拽端点)

  • 相关阅读:
    脑洞大开的爬虫解决思路 转载:https://mp.weixin.qq.com/s/Bd-wz_RiRpYv8ufIbQTZDg
    js逆向某东滑块 转载 https://mp.weixin.qq.com/s/eZSTfduYS63-LOvkAofxqA
    不能爬小程序,叫什么会爬虫 【参考资料也要看】 https://mp.weixin.qq.com/s/oDG3k_qjMZaoygZmz9OUDw
    HDU6042 Journey with Knapsack
    HDU7073 Integers Have Friends 2.0
    CF1439C Greedy Shopping
    CF813E Army Creation
    POJ1322 Chocolate
    CF451E Devu and Flowers
    POJ3734 Blocks
  • 原文地址:https://www.cnblogs.com/mooleetzi/p/11886312.html
Copyright © 2011-2022 走看看