In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)05/31 Report--
This article mainly explains "how to use Javascript to generate smooth curve", the content of the article is simple and clear, easy to learn and understand, now please follow the editor's train of thought slowly in depth, together to study and learn "how to use Javascript to generate smooth curve"!
Preface
Smooth curve generation is a very practical technique.
Most of the time, we need to draw some broken lines and then let the computer connect smoothly.
First, let's take a look at the final effect (the red is the straight line we entered, and the blue is the fitted curve). The beginning and end can be specially treated to make the graph look better:)
The realization idea is to use Bezier curve to fit.
Brief introduction of Bezier Curve
Bezier curve (B é zier curve) is a very important parametric curve in computer graphics.
Quadratic Bezier curve
The path of the quadratic Bezier curve is tracked by the function B (t) of the given points P0, P1, P2:
Cubic Bezier curve
For the cubic curve, it can be constructed by the intermediary points Q0, Q1, Q2 described by the linear Bezier curve and the points R0 and R1 described by the quadratic curve.
Bezier curve calculation function
According to the above formula, we can get the calculation function.
Second order
/ * * @ param {number} p0 * @ param {number} p1 * @ param {number} p2 * @ param {number} t * @ return {*} * @ memberof Path * / bezier2P (p0: number, p1: number, p2: number, t: number) {const P0 = p0 * Math.pow (1-t, 2); const P1 = p1 * 2 * t * (1-t); const P2 = p2 * t * t Return P0 + P1 + P2 } / * * @ param {Point} p0 * @ param {Point} p1 * @ param {Point} p2 * @ param {number} num * @ param {number} tick * @ return {Point} * @ memberof Path * / getBezierNowPoint2P (p0: Point, p1: Point, p2: Point, num: number, tick: number ): Point {x: this.bezier2P (p0.x, p1.x, p2.x, num * tick), y: this.bezier2P (p0.y, p1.y, p2.y, num * tick),} Generate quadratic Bezier curve vertex data * * @ param {Point} p0 * @ param {Point} p1 * @ param {Point} p2 * @ param {number} [num=100] * @ param {number} [tick=1] * @ return {* @ memberof Path * / create2PBezier (p0: Point, p1: Point, p2: Point Num: number = 100, tick: number = 1,) {const t = tick / (num-1) Const points = []; for (let I = 0; I
< num; i++) { const point = this.getBezierNowPoint2P(p0, p1, p2, i, t); points.push({x: point.x, y: point.y}); } return points; } 三阶 /** * 三次方塞尔曲线公式 * * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} p3 * @param {number} t * @return {*} * @memberof Path */ bezier3P(p0: number, p1: number, p2: number, p3: number, t: number) { const P0 = p0 * Math.pow(1 - t, 3); const P1 = 3 * p1 * t * Math.pow(1 - t, 2); const P2 = 3 * p2 * Math.pow(t, 2) * (1 - t); const P3 = p3 * Math.pow(t, 3); return P0 + P1 + P2 + P3; } /** * 获取坐标 * * @param {Point} p0 * @param {Point} p1 * @param {Point} p2 * @param {Point} p3 * @param {number} num * @param {number} tick * @return {*} * @memberof Path */ getBezierNowPoint3P( p0: Point, p1: Point, p2: Point, p3: Point, num: number, tick: number, ) { return { x: this.bezier3P(p0.x, p1.x, p2.x, p3.x, num * tick), y: this.bezier3P(p0.y, p1.y, p2.y, p3.y, num * tick), }; } /** * 生成三次方贝塞尔曲线顶点数据 * * @param {Point} p0 起始点 { x : number, y : number} * @param {Point} p1 控制点1 { x : number, y : number} * @param {Point} p2 控制点2 { x : number, y : number} * @param {Point} p3 终止点 { x : number, y : number} * @param {number} [num=100] * @param {number} [tick=1] * @return {Point []} * @memberof Path */ create3PBezier( p0: Point, p1: Point, p2: Point, p3: Point, num: number = 100, tick: number = 1, ) { const pointMum = num; const _tick = tick; const t = _tick / (pointMum - 1); const points = []; for (let i = 0; i < pointMum; i++) { const point = this.getBezierNowPoint3P(p0, p1, p2, p3, i, t); points.push({x: point.x, y: point.y}); } return points; }拟合算法 问题在于如何得到控制点,我们以比较简单的方法 取 p1-pt-p2的角平分线 c1c2垂直于该条角平分线 c2为p2的投影点取短边作为c1-pt c2-pt的长度对该长度进行缩放 这个长度可以大概理解为曲线的弯曲程度 ab线段 这里简单处理 只使用了二阶的曲线生成 ->? Here you can deal with it according to your own ideas.
The bc segment uses control point c2 calculated by abc and control point c3 calculated by bcd, and so on
/ * * @ param {Vector2D} p1 * @ param {Vector2D} pt * @ param {Vector2D} p2 * @ param {number} [ratio=0.3] * @ return {*} * @ memberof Path * / createSmoothLineControlPoint (p1: Vector2D, pt: Vector2D, p2: Vector2D, ratio: number = 0.3 ) {const vec1T: Vector2D = vector2dMinus (p1, pt) Const vecT2: Vector2D = vector2dMinus (p1, pt); const len1: number = vec1T.length; const len2: number = vecT2.length; const v: number = len1 / len2; let delta; if (v > 1) {delta = vector2dMinus (p1, vector2dPlus (pt, vector2dMinus (p2, pt) .scale (1 / v)) } else {delta = vector2dMinus (vector2dPlus (pt, vector2dMinus (p1, pt) .scale (v)), p2,);} delta = delta.scale (ratio); const control1: Point = {x: vector2dPlus (pt, delta). X, y: vector2dPlus (pt, delta). Y,} Const control2: Point = {x: vector2dMinus (pt, delta). X, y: vector2dMinus (pt, delta). Y,}; return {control1, control2} * * @ param {Point []} points * @ param {number} ratio * @ return {*} * @ memberof Path * / createSmoothLine (points: Point [], ratio: number = 0.3) {const len = points.length; let resultPoints = []; const controlPoints = []; if (len)
< 3) return; for (let i = 0; i < len - 2; i++) { const {control1, control2} = this.createSmoothLineControlPoint( new Vector2D(points[i].x, points[i].y), new Vector2D(points[i + 1].x, points[i + 1].y), new Vector2D(points[i + 2].x, points[i + 2].y), ratio, ); controlPoints.push(control1); controlPoints.push(control2); let points1; let points2; // 首端控制点只用一个 if (i === 0) { points1 = this.create2PBezier(points[i], control1, points[i + 1], 50); } else { console.log(controlPoints); points1 = this.create3PBezier( points[i], controlPoints[2 * i - 1], control1, points[i + 1], 50, ); } // 尾端部分 if (i + 2 === len - 1) { points2 = this.create2PBezier( points[i + 1], control2, points[i + 2], 50, ); } if (i + 2 === len - 1) { resultPoints = [...resultPoints, ...points1, ...points2]; } else { resultPoints = [...resultPoints, ...points1]; } } return resultPoints; } 案例代码 const input = [ { x: 0, y: 0 }, { x: 150, y: 150 }, { x: 300, y: 0 }, { x: 400, y: 150 }, { x: 500, y: 0 }, { x: 650, y: 150 }, ] const s = path.createSmoothLine(input); let ctx = document.getElementById("cv").getContext("2d"); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, 0); for (let i = 0; i < s.length; i++) { ctx.lineTo(s[i].x, s[i].y); } ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, 0); for (let i = 0; i < input.length; i++) { ctx.lineTo(input[i].x, input[i].y); } ctx.strokeStyle = "red"; ctx.stroke(); document.getElementById("btn").addEventListener("click", () =>{let app = document.getElementById ("app"); let index = 0; let move = () = > {if (index < s.length) {app.style.left = s [index] .x-10 + "px"; app.style.top = s [index] .y-10 + "px"; index++ RequestAnimationFrame (move)}} move () Appendix: Vector2D related code / * * @ class Vector2D * @ extends {Array} * / class Vector2D extends Array {/ * * * Creates an instance of Vector2D. * @ param {number} [Xero1] * @ param {number} [yellow0] * @ memberof Vector2D * * / constructor (x: number = 1, y: number = 0) {super (); this.x = x; this.y = y;} / * @ param {number} v * @ memberof Vector2D * / set x (v) {this [0] = v } / * @ param {number} v * @ memberof Vector2D * / set y (v) {this [1] = v;} / * @ readonly * @ memberof Vector2D * / get x () {return this [0];} / * * @ readonly * @ memberof Vector2D * / get y () {return this [1] } / * * @ readonly * @ memberof Vector2D * / get length () {return Math.hypot (this.x, this.y);} / * * @ readonly * @ memberof Vector2D * / get dir () {return Math.atan2 (this.y, this.x) } / * * @ return {* @ memberof Vector2D * / copy () {return new Vector2D (this.x, this.y);} / * * @ param {*} v * @ return {*} * @ memberof Vector2D * / add (v) {this.x + = v.x; this.y + = v.y; return this } / * * @ param {*} v * @ return {*} * @ memberof Vector2D * / sub (v) {this.x-= v.x; this.y-= v.y; return this;} / * * @ param {* @ return {Vector2D} * @ memberof Vector2D * / scale (a) {this.x * = a This.y * = a; return this;} / * * @ param {*} rad * @ return {*} * @ memberof Vector2D * / rotate (rad) {const c = Math.cos (rad); const s = Math.sin (rad); const [x, y] = this; this.x = x * c + y *-s; this.y = x * s + y * c; return this } / * * @ param {*} v * @ return {*} * @ memberof Vector2D * / cross (v) {return this.x * v.y-v.x * this.y;} / * * @ param {*} v * @ return {* @ memberof Vector2D * / dot (v) {return this.x * v.x + v.y * this.y } / * * normalized * * @ return {* @ memberof Vector2D * / normalize () {return this.scale (1 / this.length);}} / * the addition of the vector * * @ param {*} vec1 * @ param {*} vec2 * @ return {Vector2D} * / function vector2dPlus (vec1, vec2) {return new Vector2D (vec1.x + vec2.x, vec1.y + vec2.y) Param {*} vec1 * @ param {Vector2D} * @ return {Vector2D} * / function vector2dMinus (vec1, vec2) {return new Vector2D (vec1.x-vec2.x, vec1.y-vec2.y);} export {Vector2D, vector2dPlus, vector2dMinus} Thank you for your reading, the above is the content of "how to use Javascript to generate smooth curve". After the study of this article, I believe you have a deeper understanding of how to use Javascript to generate smooth curve, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.