From 83dcab57cbc70869f167aa2c69811352108bfed8 Mon Sep 17 00:00:00 2001 From: Pomax Date: Thu, 3 Sep 2020 22:21:05 -0700 Subject: [PATCH] poly-bezier --- docs/chapters/polybezier/content.en-GB.md | 18 +- docs/chapters/polybezier/handler.js | 241 ------------------ docs/chapters/polybezier/poly.js | 173 +++++++++++++ .../04bc7b98ba019a4a90bedce6e10eaf08.png | Bin 0 -> 11568 bytes .../0553872bf00ebc557f4b11d69d634fc6.png | Bin 0 -> 9217 bytes .../1a3c6b24bea874d32334d62110507fcb.png | Bin 0 -> 11568 bytes .../1aeb331a5170c203c31c55ae8d55b809.png | Bin 0 -> 9217 bytes .../408dd95905a5f001179c4da6051e49c5.svg | 2 +- .../60adbd6fe091a72e1ed37355e49a506e.png | Bin 0 -> 11568 bytes .../7afd119dd93a581ec161e2cbfc3c1e63.png | Bin 0 -> 9217 bytes .../8c1b570b3efdfbbc39ddedb4adcaaff6.svg | 2 +- .../acb8f004751017eaac4aae0b039c94cf.png | Bin 0 -> 9217 bytes .../cfbfbbc56365ba547dc7e82b329c4007.png | Bin 0 -> 11568 bytes docs/index.html | 62 ++++- docs/ja-JP/index.html | 62 ++++- docs/js/custom-element/api/graphics-api.js | 17 ++ docs/js/custom-element/api/types/bezier.js | 10 +- docs/js/custom-element/api/types/matrix.js | 8 +- docs/zh-CN/index.html | 62 ++++- 19 files changed, 367 insertions(+), 290 deletions(-) delete mode 100644 docs/chapters/polybezier/handler.js create mode 100644 docs/chapters/polybezier/poly.js create mode 100644 docs/images/chapters/polybezier/04bc7b98ba019a4a90bedce6e10eaf08.png create mode 100644 docs/images/chapters/polybezier/0553872bf00ebc557f4b11d69d634fc6.png create mode 100644 docs/images/chapters/polybezier/1a3c6b24bea874d32334d62110507fcb.png create mode 100644 docs/images/chapters/polybezier/1aeb331a5170c203c31c55ae8d55b809.png create mode 100644 docs/images/chapters/polybezier/60adbd6fe091a72e1ed37355e49a506e.png create mode 100644 docs/images/chapters/polybezier/7afd119dd93a581ec161e2cbfc3c1e63.png create mode 100644 docs/images/chapters/polybezier/acb8f004751017eaac4aae0b039c94cf.png create mode 100644 docs/images/chapters/polybezier/cfbfbbc56365ba547dc7e82b329c4007.png diff --git a/docs/chapters/polybezier/content.en-GB.md b/docs/chapters/polybezier/content.en-GB.md index 6184a7f4..1a79c52a 100644 --- a/docs/chapters/polybezier/content.en-GB.md +++ b/docs/chapters/polybezier/content.en-GB.md @@ -9,8 +9,8 @@ Unless you want sharp corners, of course. Then you don't even need 2. We'll cover three forms of poly-Bézier curves in this section. First, we'll look at the kind that just follows point 1. where the end point of a segment is the same point as the start point of the next segment. This leads to poly-Béziers that are pretty hard to work with, but they're the easiest to implement: - - + + Dragging the control points around only affects the curve segments that the control point belongs to, and moving an on-curve point leaves the control points where they are, which is not the most useful for practical modelling purposes. So, let's add in the logic we need to make things a little better. We'll start by linking up control points by ensuring that the "incoming" derivative at an on-curve point is the same as it's "outgoing" derivative: @@ -30,24 +30,24 @@ We can effect this quite easily, because we know that the vector from a curve's So let's implement that and see what it gets us. The following two graphics show a quadratic and a cubic poly-Bézier curve again, but this time moving the control points around moves others, too. However, you might see something unexpected going on for quadratic curves... - - + + -As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point's positions is different depending on whether it's the reflection of its left or right neighbouring control point: we can't even form a proper rule-conforming curve! This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little. +As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point cannot satisfy the constraint that it's the reflection of its two neighbouring control points... This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little. So: let's relax the requirement a little. We can change the constraint so that we still preserve the *angle* of the derivatives across sections (so transitions from one section to the next will still look natural), but give up the requirement that they should also have the same *vector length*. Doing so will give us a much more useful kind of poly-Bézier curve: - - + + Cubic curves are now better behaved when it comes to dragging control points around, but the quadratic poly-Bézier still has the problem that moving one control points will move the control points and may ending up defining "the next" control point in a way that doesn't work. Quadratic curves really aren't very useful to work with... Finally, we also want to make sure that moving the on-curve coordinates preserves the relative positions of the associated control points. With that, we get to the kind of curve control that you might be familiar with from applications like Photoshop, Inkscape, Blender, etc. - - + +> Again, we see that cubic curves are now rather nice to work with, but quadratic curves have a new, very serious problem: we can move an on-curve point in such a way that we can't compute what needs to "happen next". Move the top point down, below the left and right points, for instance. There is no way to preserve correct control points without a kink at the bottom point. Quadratic curves: just not that good... diff --git a/docs/chapters/polybezier/handler.js b/docs/chapters/polybezier/handler.js deleted file mode 100644 index 125d6d67..00000000 --- a/docs/chapters/polybezier/handler.js +++ /dev/null @@ -1,241 +0,0 @@ -var atan2 = Math.atan2, sqrt = Math.sqrt, sin = Math.sin, cos = Math.cos; - -module.exports = { - setupQuadratic: function(api) { - var w = api.getPanelWidth(), - h = api.getPanelHeight(), - cx = w/2, cy = h/2, pad = 40, - pts = [ - // first curve: - {x:cx,y:pad}, {x:w-pad,y:pad}, {x:w-pad,y:cy}, - // subsequent curve - {x:w-pad,y:h-pad}, {x:cx,y:h-pad}, - // subsequent curve - {x:pad,y:h-pad}, {x:pad,y:cy}, - // final curve control point - {x:pad,y:pad} - ]; - api.lpts = pts; - }, - - setupCubic: function(api) { - var w = api.getPanelWidth(), - h = api.getPanelHeight(), - cx = w/2, cy = h/2, pad = 40, - r = (w - 2*pad)/2, - k = 0.55228, - kr = k*r, - pts = [ - // first curve: - {x:cx,y:pad}, {x:cx+kr,y:pad}, {x:w-pad,y:cy-kr}, {x:w-pad,y:cy}, - // subsequent curve - {x:w-pad,y:cy+kr}, {x:cx+kr,y:h-pad}, {x:cx,y:h-pad}, - // subsequent curve - {x:cx-kr,y:h-pad}, {x:pad,y:cy+kr}, {x:pad,y:cy}, - // final curve control point - {x:pad,y:cy-kr}, {x:cx-kr,y:pad} - ]; - api.lpts = pts; - }, - - movePointsQuadraticLD: function(api, i) { - // ...we need to move _everything_ - var anchor, fixed, toMove; - for(var p=1; p<4; p++) { - anchor = i + (2*p - 2) + api.lpts.length; - anchor = api.lpts[anchor % api.lpts.length]; - fixed = i + (2*p - 1); - fixed = api.lpts[fixed % api.lpts.length]; - toMove = i + 2*p; - toMove = api.lpts[toMove % api.lpts.length]; - - toMove.x = fixed.x + (fixed.x - anchor.x); - toMove.y = fixed.y + (fixed.y - anchor.y); - } - // then, the furthest point cannot be computed properly! - toMove = i + 6; - toMove = api.lpts[toMove % api.lpts.length]; - api.problem = toMove; - }, - - movePointsCubicLD: function(api, i) { - var toMove, fixed; - if (i%3 === 1) { - fixed = i-1; - fixed += (fixed < 0) ? api.lpts.length : 0; - toMove = i-2; - toMove += (toMove < 0) ? api.lpts.length : 0; - } else { - fixed = (i+1) % api.lpts.length; - toMove = (i+2) % api.lpts.length; - } - fixed = api.lpts[fixed]; - toMove = api.lpts[toMove]; - toMove.x = fixed.x + (fixed.x - api.mp.x); - toMove.y = fixed.y + (fixed.y - api.mp.y); - }, - - linkDerivatives: function(evt, api) { - if (api.mp) { - var quad = api.lpts.length === 8; - var i = api.mp_idx; - if (quad) { - if (i%2 !== 0) { this.movePointsQuadraticLD(api, i); } - } else { - if(i%3 !== 0) { this.movePointsCubicLD(api, i); } - } - } - }, - - movePointsQuadraticDirOnly: function(api, i) { - // ...we need to move _everything_ ...again - var anchor, fixed, toMove; - - // move left and right - [-1,1].forEach(v => { - anchor = api.mp; - fixed = i + v + api.lpts.length; - fixed = api.lpts[fixed % api.lpts.length]; - toMove = i + 2*v + api.lpts.length; - toMove = api.lpts[toMove % api.lpts.length]; - var a = atan2(fixed.y - anchor.y, fixed.x - anchor.x), - dx = toMove.x - fixed.x, - dy = toMove.y - fixed.y, - d = sqrt(dx*dx + dy*dy); - toMove.x = fixed.x + d*cos(a); - toMove.y = fixed.y + d*sin(a); - }); - - // then, the furthest point cannot be computed properly! - toMove = i + 4; - toMove = api.lpts[toMove % api.lpts.length]; - api.problem = toMove; - }, - - movePointsCubicDirOnly: function(api, i) { - var toMove, fixed; - if (i%3 === 1) { - fixed = i-1; - fixed += (fixed < 0) ? api.lpts.length : 0; - toMove = i-2; - toMove += (toMove < 0) ? api.lpts.length : 0; - } else { - fixed = (i+1) % api.lpts.length; - toMove = (i+2) % api.lpts.length; - } - fixed = api.lpts[fixed]; - toMove = api.lpts[toMove]; - var a = atan2(fixed.y - api.mp.y, fixed.x - api.mp.x), - dx = toMove.x - fixed.x, - dy = toMove.y - fixed.y, - d = sqrt(dx*dx + dy*dy); - toMove.x = fixed.x + d*cos(a); - toMove.y = fixed.y + d*sin(a); - }, - - linkDirection: function(evt, api) { - if (api.mp) { - var quad = api.lpts.length === 8; - var i = api.mp_idx; - if (quad) { - if(i%2 !== 0) { this.movePointsQuadraticDirOnly(api, i); } - } else { - if(i%3 !== 0) { this.movePointsCubicDirOnly(api, i); } - } - } - }, - - bufferPoints: function(evt, api) { - api.bpts = JSON.parse(JSON.stringify(api.lpts)); - }, - - moveQuadraticPoint: function(api, i) { - this.moveCubicPoint(api,i); - - // then move the other control points - [-1,1].forEach(v => { - var anchor = i - v + api.lpts.length; - anchor = api.lpts[anchor % api.lpts.length]; - var fixed = i - 2*v + api.lpts.length; - fixed = api.lpts[fixed % api.lpts.length]; - var toMove = i - 3*v + api.lpts.length; - toMove = api.lpts[toMove % api.lpts.length]; - var a = atan2(fixed.y - anchor.y, fixed.x - anchor.x), - dx = toMove.x - fixed.x, - dy = toMove.y - fixed.y, - d = sqrt(dx*dx + dy*dy); - toMove.x = fixed.x + d*cos(a); - toMove.y = fixed.y + d*sin(a); - }); - - // then signal a problem - var toMove = i + 4; - toMove = api.lpts[toMove % api.lpts.length]; - api.problem = toMove; - }, - - moveCubicPoint: function(api, i) { - var op = api.bpts[i], - np = api.lpts[i], - dx = np.x - op.x, - dy = np.y - op.y, - len = api.lpts.length, - l = i-1+len, - r = i+1, - // original left and right - ol = api.bpts[l % len], - or = api.bpts[r % len], - // current left and right - nl = api.lpts[l % len], - nr = api.lpts[r % len]; - // update current left - nl.x = ol.x + dx; - nl.y = ol.y + dy; - // update current right - nr.x = or.x + dx; - nr.y = or.y + dy; - return {x:dx, y:dy}; - }, - - modelCurve: function(evt, api) { - if (api.mp) { - var quad = api.lpts.length === 8; - var i = api.mp_idx; - if (quad) { - if (i%2 !== 0) { this.movePointsQuadraticDirOnly(api, i); } - else { this.moveQuadraticPoint(api, i); } - } - else { - if(i%3 !== 0) { this.movePointsCubicDirOnly(api, i); } - else { this.moveCubicPoint(api, i); } - } - } - }, - - draw: function(api, curves) { - api.reset(); - var pts = api.lpts; - var quad = pts.length === 8; - - var c1 = quad ? new api.Bezier(pts[0],pts[1],pts[2]) : new api.Bezier(pts[0],pts[1],pts[2],pts[3]); - api.drawSkeleton(c1, false, true); - api.drawCurve(c1); - - var c2 = quad ? new api.Bezier(pts[2],pts[3],pts[4]) : new api.Bezier(pts[3],pts[4],pts[5],pts[6]); - api.drawSkeleton(c2, false, true); - api.drawCurve(c2); - - var c3 = quad ? new api.Bezier(pts[4],pts[5],pts[6]) : new api.Bezier(pts[6],pts[7],pts[8],pts[9]); - api.drawSkeleton(c3, false, true); - api.drawCurve(c3); - - var c4 = quad ? new api.Bezier(pts[6],pts[7],pts[0]) : new api.Bezier(pts[9],pts[10],pts[11],pts[0]); - api.drawSkeleton(c4, false, true); - api.drawCurve(c4); - - if (api.problem) { - api.setColor("red"); - api.drawCircle(api.problem,5); - } - } -}; diff --git a/docs/chapters/polybezier/poly.js b/docs/chapters/polybezier/poly.js new file mode 100644 index 00000000..a174f3c1 --- /dev/null +++ b/docs/chapters/polybezier/poly.js @@ -0,0 +1,173 @@ +let points; + +setup() { + var w = this.width, + h = this.height, + cx = w/2, + cy = h/2, + pad = 40, + type = this.type = this.parameters.type ?? `quadratic`; + + if (type === `quadratic`) { + points = [ + // first curve: + {x:cx,y:pad}, {x:w-pad,y:pad}, {x:w-pad,y:cy}, + // subsequent curve + {x:w-pad,y:h-pad}, {x:cx,y:h-pad}, + // subsequent curve + {x:pad,y:h-pad}, {x:pad,y:cy}, + // final curve control point + {x:pad,y:pad} + ]; + } else { + let r = (w - 2*pad)/2, + k = 0.55228, + kr = k*r; + points = [ + // first curve: + {x:cx,y:pad}, {x:cx+kr,y:pad}, {x:w-pad,y:cy-kr}, {x:w-pad,y:cy}, + // subsequent curve + {x:w-pad,y:cy+kr}, {x:cx+kr,y:h-pad}, {x:cx,y:h-pad}, + // subsequent curve + {x:cx-kr,y:h-pad}, {x:pad,y:cy+kr}, {x:pad,y:cy}, + // final curve control point + {x:pad,y:cy-kr}, {x:cx-kr,y:pad} + ]; + } + setMovable(points); +} + +draw() { + clear() + var pts = points; + var quad = pts.length === 8; + + var c1 = quad ? new Bezier(this, pts[0],pts[1],pts[2]) : new Bezier(this, pts[0],pts[1],pts[2],pts[3]); + c1.drawSkeleton(); + c1.drawCurve(); + c1.drawPoints(false); + + var c2 = quad ? new Bezier(this, pts[2],pts[3],pts[4]) : new Bezier(this, pts[3],pts[4],pts[5],pts[6]); + c2.drawSkeleton(); + c2.drawCurve(); + c2.drawPoints(false); + + var c3 = quad ? new Bezier(this, pts[4],pts[5],pts[6]) : new Bezier(this, pts[6],pts[7],pts[8],pts[9]); + c3.drawSkeleton(); + c3.drawCurve(); + c3.drawPoints(false); + + var c4 = quad ? new Bezier(this, pts[6],pts[7],pts[0]) : new Bezier(this, pts[9],pts[10],pts[11],pts[0]); + c4.drawSkeleton(); + c4.drawCurve(); + c4.drawPoints(false); + + if (this.problem) { + noFill(); + setStroke(`red`); + circle(this.problem.x, this.problem.y, 7); + } +} + +movePointsQuadratic(i, link) { + const l = points.length; + if (link === `conventional` && i%2 === 0) { + let ppl = points[(l+i-3)%l]; + let pl = points[(l+i-1)%l]; + let pr = points[(l+i+1)%l]; + let ppr = points[(l+i+3)%l]; + pl.x += this.currentPoint.diff.x; + pl.y += this.currentPoint.diff.y; + pr.x += this.currentPoint.diff.x; + pr.y += this.currentPoint.diff.y; + ppl.x -= this.currentPoint.diff.x; + ppl.y -= this.currentPoint.diff.y; + ppr.x -= this.currentPoint.diff.x; + ppr.y -= this.currentPoint.diff.y; + + this.problem = points[(l+i+4)%l]; + if (ppr.y === this.problem.y) { + this.problem = false; + } + } + + if (i%2 === 1) { + let c1 = points[(l+i-2)%l]; + let p1 = points[(l+i-1)%l]; + let p2 = points[(l+i+1)%l]; + let c2 = points[(l+i+2)%l]; + let p3 = points[(l+i+3)%l]; + let c3 = points[(l+i+4)%l]; + let p4 = points[(l+i+5)%l]; + if (link === `derivative`) { + c1.x = p1.x + (p1.x - this.currentPoint.x) + c1.y = p1.y + (p1.y - this.currentPoint.y) + c2.x = p2.x + (p2.x - this.currentPoint.x) + c2.y = p2.y + (p2.y - this.currentPoint.y) + c3.x = p3.x + (p3.x - c2.x) + c3.y = p3.y + (p3.y - c2.y) + this.problem = false; + if (c3.x !== p4.x + (p4.x - c1.x) || c3.y !== p4.y + (p4.y - c1.y)) { + this.problem = c3; + } + } + if (link === `direction` || link === `conventional`) { + let a1 = atan2(this.currentPoint.y-p1.y,this.currentPoint.x-p1.x) + PI; + let d1 = dist(c1.x, c1.y, p1.x, p1.y); + c1.x = p1.x + d1 * cos(a1); + c1.y = p1.y + d1 * sin(a1); + let a2 = atan2(this.currentPoint.y-p2.y,this.currentPoint.x-p2.x) + PI; + let d2 = dist(c2.x, c2.y, p2.x, p2.y); + c2.x = p2.x + d2 * cos(a2); + c2.y = p2.y + d2 * sin(a2); + this.problem = c3; + } + } +} + +movePointsCubic(i, link) { + const l = points.length; + if (link === `conventional` && i%3 === 0) { + let left = points[(l+i-1)%l]; + left.x += this.currentPoint.diff.x; + left.y += this.currentPoint.diff.y; + let right = points[(l+i+1)%l]; + right.x += this.currentPoint.diff.x; + right.y += this.currentPoint.diff.y; + } + + if (i%3 > 0) { + let c, p; + if (i%3 === 1) { + c = points[(l+i-2)%l]; + p = points[(l+i-1)%l]; + } + if (i%3 === 2) { + c = points[(l+i+2)%l]; + p = points[(l+i+1)%l]; + } + if (link === `derivative`) { + c.x = p.x + (p.x - this.currentPoint.x) + c.y = p.y + (p.y - this.currentPoint.y) + } + if (link === `direction` || link === `conventional`) { + let a = atan2(this.currentPoint.y-p.y,this.currentPoint.x-p.x) + PI; + let d = dist(c.x, c.y, p.x, p.y); + c.x = p.x + d * cos(a); + c.y = p.y + d * sin(a); + } + } +} + +onMouseMove() { + if (this.currentPoint) { + const position = points.indexOf(this.currentPoint); + const link = this.parameters.link; + if (this.type === `quadratic`) { + this.movePointsQuadratic(position, link); + } else { + this.movePointsCubic(position, link); + } + redraw(); + } +} diff --git a/docs/images/chapters/polybezier/04bc7b98ba019a4a90bedce6e10eaf08.png b/docs/images/chapters/polybezier/04bc7b98ba019a4a90bedce6e10eaf08.png new file mode 100644 index 0000000000000000000000000000000000000000..3d02bdbb63809602d16d4ea973c8903bb7171b0d GIT binary patch literal 11568 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 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/polybezier/0553872bf00ebc557f4b11d69d634fc6.png b/docs/images/chapters/polybezier/0553872bf00ebc557f4b11d69d634fc6.png new file mode 100644 index 0000000000000000000000000000000000000000..f9579b1180bc54291c93b61ddb77e0cbc0e4d707 GIT binary patch literal 9217 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 Rz;Aj`viB9G@+1ts{|g9<@wxy2 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/polybezier/1a3c6b24bea874d32334d62110507fcb.png b/docs/images/chapters/polybezier/1a3c6b24bea874d32334d62110507fcb.png new file mode 100644 index 0000000000000000000000000000000000000000..3d02bdbb63809602d16d4ea973c8903bb7171b0d GIT binary patch literal 11568 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 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/polybezier/1aeb331a5170c203c31c55ae8d55b809.png b/docs/images/chapters/polybezier/1aeb331a5170c203c31c55ae8d55b809.png new file mode 100644 index 0000000000000000000000000000000000000000..f9579b1180bc54291c93b61ddb77e0cbc0e4d707 GIT binary patch literal 9217 zcmdUVXHXPvx9zB}ii)73D3SzW5Xm4&MuL)toMlKNAd+#&Nf8NxgGe07IcFq;NREOc zA{iuu1Odt6?DqYBoT_uGZry+PmSt)8)7?+n&)RFPJpsy!(&x`!KZ`=4&dbV3siIKF z$dJE8r{K<&%%A1(c9(o(1+>*Sq@#X0@ibj;NdDz#WDU5;z7S)8kMvbGpBbyMZ()wWRR z`c?Is`F6r{|FiASbC1!lbzC$J+c`9H?MJ`1|1?`^I!a2~@+@YtE>K|I#pPfd8{aX7 z6O1LIlM-^tAi3dVdtMbSL8KrjBgkA=T}nwkBy9ccP&pPl$4b4Bv-ttua~HkwfjvyHS1^K6kT0yD<>y`x^?T; zTqAC|A;VbwE|Xz?oZ;;cWrs7`)SBb%zo(>WJ-$&CVincY$Q08<1Fv#?{q_yF)L~sV zxwO@5_%LGLn)f6ciMGSn^$`r2M_H z(fF8qVs_TaYJ6{Z_vg}*g0gZC+ktS^h@y!JBScABTAIa4hu=T%$0#yIau_sQ@=dO+ z1n1{-96NR_s>`&}Vex^X;SCYDO@iaA>O-p z)pT@Zt*qE!)6_LIRNw+8(GpDC^7O;k;bDxkGry6Mk(88_VWGBvP*CHe!tsg3=;T$! z4|bEye8I1*M=Bj26;bvo5VTpzpFVvWb&WIR-OM{$Di+7Yb7Uvb$1l)$9!$Du;g*L5 z*4Ebe-M2Yky?PbHZ|6-T;@VSYV*rB}+x-$8#cgtSVq)T-Q>RK7&CXxrd|qAczPowg zEB>;*wPSB$Px#5(@VU9y7DHqH!NH_3B%fEWK2$1rc!-#on1n?{sA_69f6vurW@n$- z-&sf2;_zUP$9dK8)cNaD`T8}3fA%O|skC_Kv7h(a_#%xhx1AWAE+E?^Lv5_jw>Ymm z>*!G6}IsNj~d3rv+2>4X*N3SEt$mTbeW3{nGMMV~ozQsk$ ziIsyGW#yZ)vP^k;*Gsioh4)t*s3VeVYvYoogY7rwR9?S+-P+O7(9sb{C+Yk4?b~}2 z67}ch+gpPK$#H6E+w}lJ2#J)Gl)0x#if($9xPakdtmDe4f~hH*FZzv-&p*B-)N&FM z$1h&I7#qiY^XAK9GhMN7D!k^oB_&}oF;qpx#cgeEpT@@Gr=}i1cys-}ySuPn<(#Q> z)kqLOIZgv@n;ITWBO+&RKL0@{N?crA>i+$T&gxTs4dR-bNQwbE(jb7KG*f!~h)%9ShbJJXTXn}ZgBD64bH!Q6H~rCc}W5(U%bL%HW~ zwBV_Y4|f0j8vGD=n%4d8{Xp`zk>6!%vgJVxJGT#=66p z)%*hjRH(l&$`YQyj(g+kN?- z_ib%Cd()Men3-iAgd^!ql0s_SwuiV1tYdK;rOeiVJ6y`;vesA zE>-W$MCV{D-cj(Faz1J#>idoL4wDs{o}DeW9N>Qc{(Tg$1vzYUW%>1+dELFep}!|v zc&vx{VHM}!Y-V+}fmA-=nt$8l zN8d737?_yWcV^?)zshr5q@?WN@ceyFuj@ANrLF3nMCxCTLfM+RkD7xh8k?F5&3npiPWvgD zz7VO?^8>|9`L(;Z-8O$sglp;3F*66u#<`Jrd3p7H!6|KGtbam?VhG$P(|g-sA8*|M ziGF~mLjHSCUjCet$e+u8q_mpUvRjY4Q?5W>*cx>Uc3AxWJKNykwI7YEj03}$w*7+x zm)}iScYX$P0016?T@haIP4Pj-z_@I4s%zM!FcIkdUqegI>s& zwcK3YvLe`feUCpHzUL{^1o1tEa6Xo+*A?|$=NaKpwA>69P7-{_E<-?3@>z~U(3&;9 zz9Of|N7l?^`GZq4NBdK8x2Qb8V5-t_1cj0U1npQT3cIf_ay9wxOX6!2FmSjvS{YK zW#LQGgKX1aaI~w%XFc2sBUNuvX=dwq3aNbd?RTO@RC%^sQb z;dYDIr7Krb1@X4xU%q@{)vt~k+n>1`78#k1@68-e!$4|wIoz3bS+1Cc6rn{eU0whH zI@3vLSnn1aTaYZlhUkU`^v+LBM;f5HxI%zLs5?+iobueCqz#RVYVF|o7=)))NM$a& z6$(fd4`+(YW>mOO#fOq`*M?^HbL=E6vlex#TDd#nGC6sX^@!l8^W^yv5k-}9J`N5J z4EF7@Rn#A3TWDhmz zhzNQ6wr=iAvWE0UYs=0kE&!(0S+OG>hcJ@qA`|=Zx?{Dw3oL*;`GT)6bjFLtcXnb( zsQ42E<^1g0xXrDtO@IGvV#StUC?3cW#9si00ioJTd$cY6J~~>XW&Q%Y4jKUoE-tR3 z?c$zrNEN$(7F)&+H}CeT2>Nt{%R<@%`dLUdN~HH*%u6(y&&s}Sppab)-4VfdQ$!?o zw8kwPPv1zou{;u8QgSC!m|{`Y%4_q@9hcP zc7m}8u64$V=+X=@^LH@qlA#pYP&ix(sj2rJ!iG$La0>uI(yMZ0M57-#T&5djs6)*wzKhI2|$!CUA#!=$6wEQ^5jXQLT%y- z+jkS~kGtbUij+%i%^_*|VrLs|O^Ph~*@2#<3i@84MhgfKfCXgZ?K+4x&}N@w5-TbQ zt*tV!o^zZkDk^t)dF^I8Df(2b0}|V(#y`DeK%?6$8S7IC7&JnM934v+Zk08@1;Lmt zkHH{MWEl@%k_>N4l=QnM>|C&LO#)XAeCyisYrIi=N>b8spgY>yQLx^)a?os$je#;` zC6^G4+NWAWZbGhW+qpDBjzNRPV zPHqoSmW8L2O0R${W6~{U!N$ghklI?0y(~OE+=k4>Z}-#3NYj8vir{|mrysX68e3O) z51Hki7cX7_(FM75qzhefNfE-r!dmqMY~?-nHd9klq@WwP86)iSE+gX>(mxIm4=z>z zZ2-C}M<6P@OhM5G1V+8(37KSAK;P5wwx{)MK(19ZHPZwiM9tE;IHCEBhqUyEVKmOqb=r#(D8%t|KuG7qWo_xk!|{i}0X$-`mG9Vw-y5mn2T z@(^iZ6^nUQ8QIxt)RSpA12jklA75XXz7IF(j&I+;XW{MCDmg-ZeNRFD(`dOMK@j!W z?dj=B5NuYEB@iV(qobo!ML&G<2+9; z*O8K$Df?QAsII#^I4ungM?aMvx#ib~jGov&@Lew8TIIgvYW(>}eRs<(KVD8|{751GGhnNL{gl7(ZS`{2WcnQqX_SdSdhPFzt)L#MJKbMBdi&I~S4)0sw(=yogIqGb?Tzrq_BxW z09ZeMXuFIS*a~U2)B^>X8~ngRhQ{xca;QT8vucNWQKN2hn+fEC*EuFV+BCqd@74yQ_I$iq9ki}|UT z5-^y6W27Y}iX$MR_pcRV|5=K~Y1AeCS1eH(Zg<0cxpvRGk87~;g2^Qc3cw-_YDs@Z zvkwmg_8pIz*8l|i`1z^rE~$;bvSrfD4qsih{m;`^t~5b{1L8Sgm29%_{cvKj0MragPT+SHx)A6xpTRApfiAsNnQG4QUjHkXUy~GsK2IM z1-wf3{Nl|A1x_pa$Q(G4WRJ+uAYIdPZVCZ=1`t($hY?C3$lBW%!7w^){|>|4JX2U+ zx;$lJ;c1R$_Jm@s_py#fFf8C}tNC6B^03Nx${>9&SFMPSh-q!R0x>`tx8O~H5F>zG z5i8`x?f6R@PDUVI2Lp&UXlzTw+cJZjNhRbMG|}Mq9|kfyIvRAH_ce$c$dNv#rPd?u z87j$$e@Z=FdaVe9Y7VCDj$qS8V3$X?)Y7Ql=L}>BzJ`c4SjY<732)XY2CRgN%0)O= z40Lqj|5B#ktE)G7dBYW=`7$B(R#^>}1b|p-$jNdPX;vV?#PEl}5bY=GPyS_WkW0pa z>Q8~*FI>2_^k|M7(VY!`q_e=7{SYcz3a-VwckjTMP5<|SV=_ugvkjzTDF{ouOlLhX z-4QuZU~~d>8w6eSL`RC((INN}tqgodGD1$vK;Rpd&qLplnXk{b7(*n9 zP-379n0Qe=hsz4(QUnG@Mk8)QYiFlA!eTo*J0W@-3V8I7Lgm8(K(B*%$7OxVwlrM$iiSF%esd zK|$8819w#id;tKipt~h@#v9 zS&ul3&b#yJ8q)KZtyPef7u%m81;^v9lGwptl_|P2MFuCkmG*G;bmV((ubc1~%Cwlk zC?Byp6Kw-xDjP;-1k+$OsEvWU0K1^w?pT9OXyW*bCBM2JPNRiloNy+hfEgJXLGiuS z(syZMG^-f(*9|{|C3qDXemWlKv8e<5n+#9U0lA(4COY}*s=n>~4nwXTl0HdAy=Dkz zQ9NdN;e72UNtKoF!6ZV$l*V)|=KH1Rk?(@O2cQKE17$uBbsR&0NM#R<3#r zY?l3guY;?g5wj+VPB62vnLuc#q^DPTggg&Bg94Aj6s*0@_q>5Xv@`HGiO1_+oIoyN zXytzryPOFN2Xk8Mx;s_?EzIv0-*Q*r>+0$(0tWyLK*t+o;2AFOg2)Gm zFavvyRj)D(Vfi6A+06-EINVX99)gm-#1mjT%ph}$73!bvPq}c^Vp?1X4$tPwSU06j z^(P=j8q!~R2Y4z1KD|6$?0Mh{Oc5-tFjmziG%QVnnv%#XkifL=t1m9gQntp)QbObw z+fGOzL6x0f+g@rl6b0HHstW4V3QuxCr$P`ZYiqaKc&<}kA|um~<|c;Ep9}~Hu>4W* z0y1zKhENZOdrBpR9aJKsap8`4(<37|S*i?WGVN33E^cl-#?8cRw-A+1?vF z`V7$olHD;n{6kRZJnkKV&;~85fBsCDeLTq3Wv5JFWDa$_&S!ZIMqms(jhLckW1fiT z08ZrU#)dkz(!O6uBuBBwo+Ie=mw+D6W;%@;{V!%2SNy|F_9o~Wmp76J!3qG>?HaQA z*ww2f*5z}CY!%T8-Aj7a&LM2NrK^W~D`ZquozJ>OTEJD*Xt8HjMPHYflcWDPffd3I zXy#$tPLK-MB?pVP!`5lEJQLd4+1X!@Kbit`x_a|L(74y(tk++sxC5MG+*@E8m^;^=n)&l9NBcVq@g7MbG%DK>HWMB5p1XNvo@029iQdD;hI5_e2kS9x9xZAd7!k zmRcOmtgI-(JM1L=pd|rx;I$CgHpKUVwPIv^1=)QP3Vni)swkiWkcEK~(2r6pN36xAg9a9$lRc(PwM6I*#F(4uBBDB>k8W* zp0lO;@S&WdA_-EAnVK4hK>*+<%c5>d9b8fwReydOGpBN!&N#zSID^ep-Hn7#_F4f?fF#|Sy$ ztE+{<+rbza(J?8;AR2dLY3OQTlLT}IH6I|&WmS*C*xWH35sbOlZg42!?0HC9%1n93 zf2r8)#M`*I(dDX)#l=Nt7M5fv2^AG_=V-D(WdcOGeYeO~4@~hCDNQH9i^HFfw$gu# zv7U*2Pfz9?xYeOhC$f;=0vJAPn4zt9K}D7~LW#C>kvI73SJjc~7u300`T9XLBJUx5 zPxSov@*@IU;GatA=um(>g32Gz&@&_?XnuacyWO5#-MdhqQG{{`wB{b>K!rD^j=HI- zpY77~)oNi0Ik^mfd|E=nbJ~MB>0Hl`Gc%^QSy(cG*5~EnA=MxkIXP2+!cgi2lkf~F zDHAJekiS0>q<|KrW&u@08k%L7GCwHkS+}Ru*3vvzbz5X<)cx-TVjM6{>;A+3Q;6{Z zfVjKssu;sB4smt<{CTjMjEV=ISXwsr_5!8y0Vf2wQ~%-S<|g{qEq^eiT)p;;tQBap z!(Y!mfudX&KwQDl5@JsQTe0vGidAGcs0|vhY#tknH#jI7S}Jq@ zwKO>?2`dLky1l!rzX!Fc1}HZ#E)K;RNSC~bYlitUKqsJR>8o$@e|P^?Iiy|9S{JT& z)I#f3P1alCcd)k=8X4K56FBWVq~WpWs;c^KIBo10c=SJJ3So1~6fus*l>)auxbGc{ zg?cS}|9m++&gfB{)Ob5}m4qAUo4SA8d&@XXUY^o(qFhW6SC^7D7}9^zonidx*_WjI zf$DxJqO)g{%FC~zq*CI4@tB6`4*`9#YZmgyE2(W7Rb^ znR$6>d3hv@5?L=(oyo7Z4)?d)+r$>Dw7t zPe#TjEB1?7?*Isaed>DX^`-DSJ!&jW$ObM$=7^|zq`Jw|2c{ZSGNGuoc&Rt#%{U+! z7%Ku;d0_BMID#O`_G9MI9 Rz;Aj`viB9G@+1ts{|g9<@wxy2 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/polybezier/408dd95905a5f001179c4da6051e49c5.svg b/docs/images/chapters/polybezier/408dd95905a5f001179c4da6051e49c5.svg index 4f06b843..a2e31452 100644 --- a/docs/images/chapters/polybezier/408dd95905a5f001179c4da6051e49c5.svg +++ b/docs/images/chapters/polybezier/408dd95905a5f001179c4da6051e49c5.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/images/chapters/polybezier/60adbd6fe091a72e1ed37355e49a506e.png b/docs/images/chapters/polybezier/60adbd6fe091a72e1ed37355e49a506e.png new file mode 100644 index 0000000000000000000000000000000000000000..3d02bdbb63809602d16d4ea973c8903bb7171b0d GIT binary patch literal 11568 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 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/polybezier/7afd119dd93a581ec161e2cbfc3c1e63.png b/docs/images/chapters/polybezier/7afd119dd93a581ec161e2cbfc3c1e63.png new file mode 100644 index 0000000000000000000000000000000000000000..f9579b1180bc54291c93b61ddb77e0cbc0e4d707 GIT binary patch literal 9217 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 Rz;Aj`viB9G@+1ts{|g9<@wxy2 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/polybezier/8c1b570b3efdfbbc39ddedb4adcaaff6.svg b/docs/images/chapters/polybezier/8c1b570b3efdfbbc39ddedb4adcaaff6.svg index dd042e94..341af24b 100644 --- a/docs/images/chapters/polybezier/8c1b570b3efdfbbc39ddedb4adcaaff6.svg +++ b/docs/images/chapters/polybezier/8c1b570b3efdfbbc39ddedb4adcaaff6.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/images/chapters/polybezier/acb8f004751017eaac4aae0b039c94cf.png b/docs/images/chapters/polybezier/acb8f004751017eaac4aae0b039c94cf.png new file mode 100644 index 0000000000000000000000000000000000000000..f9579b1180bc54291c93b61ddb77e0cbc0e4d707 GIT binary patch literal 9217 zcmdUVXHXPvx9zB}ii)73D3SzW5Xm4&MuL)toMlKNAd+#&Nf8NxgGe07IcFq;NREOc zA{iuu1Odt6?DqYBoT_uGZry+PmSt)8)7?+n&)RFPJpsy!(&x`!KZ`=4&dbV3siIKF z$dJE8r{K<&%%A1(c9(o(1+>*Sq@#X0@ibj;NdDz#WDU5;z7S)8kMvbGpBbyMZ()wWRR z`c?Is`F6r{|FiASbC1!lbzC$J+c`9H?MJ`1|1?`^I!a2~@+@YtE>K|I#pPfd8{aX7 z6O1LIlM-^tAi3dVdtMbSL8KrjBgkA=T}nwkBy9ccP&pPl$4b4Bv-ttua~HkwfjvyHS1^K6kT0yD<>y`x^?T; zTqAC|A;VbwE|Xz?oZ;;cWrs7`)SBb%zo(>WJ-$&CVincY$Q08<1Fv#?{q_yF)L~sV zxwO@5_%LGLn)f6ciMGSn^$`r2M_H z(fF8qVs_TaYJ6{Z_vg}*g0gZC+ktS^h@y!JBScABTAIa4hu=T%$0#yIau_sQ@=dO+ z1n1{-96NR_s>`&}Vex^X;SCYDO@iaA>O-p z)pT@Zt*qE!)6_LIRNw+8(GpDC^7O;k;bDxkGry6Mk(88_VWGBvP*CHe!tsg3=;T$! z4|bEye8I1*M=Bj26;bvo5VTpzpFVvWb&WIR-OM{$Di+7Yb7Uvb$1l)$9!$Du;g*L5 z*4Ebe-M2Yky?PbHZ|6-T;@VSYV*rB}+x-$8#cgtSVq)T-Q>RK7&CXxrd|qAczPowg zEB>;*wPSB$Px#5(@VU9y7DHqH!NH_3B%fEWK2$1rc!-#on1n?{sA_69f6vurW@n$- z-&sf2;_zUP$9dK8)cNaD`T8}3fA%O|skC_Kv7h(a_#%xhx1AWAE+E?^Lv5_jw>Ymm z>*!G6}IsNj~d3rv+2>4X*N3SEt$mTbeW3{nGMMV~ozQsk$ ziIsyGW#yZ)vP^k;*Gsioh4)t*s3VeVYvYoogY7rwR9?S+-P+O7(9sb{C+Yk4?b~}2 z67}ch+gpPK$#H6E+w}lJ2#J)Gl)0x#if($9xPakdtmDe4f~hH*FZzv-&p*B-)N&FM z$1h&I7#qiY^XAK9GhMN7D!k^oB_&}oF;qpx#cgeEpT@@Gr=}i1cys-}ySuPn<(#Q> z)kqLOIZgv@n;ITWBO+&RKL0@{N?crA>i+$T&gxTs4dR-bNQwbE(jb7KG*f!~h)%9ShbJJXTXn}ZgBD64bH!Q6H~rCc}W5(U%bL%HW~ zwBV_Y4|f0j8vGD=n%4d8{Xp`zk>6!%vgJVxJGT#=66p z)%*hjRH(l&$`YQyj(g+kN?- z_ib%Cd()Men3-iAgd^!ql0s_SwuiV1tYdK;rOeiVJ6y`;vesA zE>-W$MCV{D-cj(Faz1J#>idoL4wDs{o}DeW9N>Qc{(Tg$1vzYUW%>1+dELFep}!|v zc&vx{VHM}!Y-V+}fmA-=nt$8l zN8d737?_yWcV^?)zshr5q@?WN@ceyFuj@ANrLF3nMCxCTLfM+RkD7xh8k?F5&3npiPWvgD zz7VO?^8>|9`L(;Z-8O$sglp;3F*66u#<`Jrd3p7H!6|KGtbam?VhG$P(|g-sA8*|M ziGF~mLjHSCUjCet$e+u8q_mpUvRjY4Q?5W>*cx>Uc3AxWJKNykwI7YEj03}$w*7+x zm)}iScYX$P0016?T@haIP4Pj-z_@I4s%zM!FcIkdUqegI>s& zwcK3YvLe`feUCpHzUL{^1o1tEa6Xo+*A?|$=NaKpwA>69P7-{_E<-?3@>z~U(3&;9 zz9Of|N7l?^`GZq4NBdK8x2Qb8V5-t_1cj0U1npQT3cIf_ay9wxOX6!2FmSjvS{YK zW#LQGgKX1aaI~w%XFc2sBUNuvX=dwq3aNbd?RTO@RC%^sQb z;dYDIr7Krb1@X4xU%q@{)vt~k+n>1`78#k1@68-e!$4|wIoz3bS+1Cc6rn{eU0whH zI@3vLSnn1aTaYZlhUkU`^v+LBM;f5HxI%zLs5?+iobueCqz#RVYVF|o7=)))NM$a& z6$(fd4`+(YW>mOO#fOq`*M?^HbL=E6vlex#TDd#nGC6sX^@!l8^W^yv5k-}9J`N5J z4EF7@Rn#A3TWDhmz zhzNQ6wr=iAvWE0UYs=0kE&!(0S+OG>hcJ@qA`|=Zx?{Dw3oL*;`GT)6bjFLtcXnb( zsQ42E<^1g0xXrDtO@IGvV#StUC?3cW#9si00ioJTd$cY6J~~>XW&Q%Y4jKUoE-tR3 z?c$zrNEN$(7F)&+H}CeT2>Nt{%R<@%`dLUdN~HH*%u6(y&&s}Sppab)-4VfdQ$!?o zw8kwPPv1zou{;u8QgSC!m|{`Y%4_q@9hcP zc7m}8u64$V=+X=@^LH@qlA#pYP&ix(sj2rJ!iG$La0>uI(yMZ0M57-#T&5djs6)*wzKhI2|$!CUA#!=$6wEQ^5jXQLT%y- z+jkS~kGtbUij+%i%^_*|VrLs|O^Ph~*@2#<3i@84MhgfKfCXgZ?K+4x&}N@w5-TbQ zt*tV!o^zZkDk^t)dF^I8Df(2b0}|V(#y`DeK%?6$8S7IC7&JnM934v+Zk08@1;Lmt zkHH{MWEl@%k_>N4l=QnM>|C&LO#)XAeCyisYrIi=N>b8spgY>yQLx^)a?os$je#;` zC6^G4+NWAWZbGhW+qpDBjzNRPV zPHqoSmW8L2O0R${W6~{U!N$ghklI?0y(~OE+=k4>Z}-#3NYj8vir{|mrysX68e3O) z51Hki7cX7_(FM75qzhefNfE-r!dmqMY~?-nHd9klq@WwP86)iSE+gX>(mxIm4=z>z zZ2-C}M<6P@OhM5G1V+8(37KSAK;P5wwx{)MK(19ZHPZwiM9tE;IHCEBhqUyEVKmOqb=r#(D8%t|KuG7qWo_xk!|{i}0X$-`mG9Vw-y5mn2T z@(^iZ6^nUQ8QIxt)RSpA12jklA75XXz7IF(j&I+;XW{MCDmg-ZeNRFD(`dOMK@j!W z?dj=B5NuYEB@iV(qobo!ML&G<2+9; z*O8K$Df?QAsII#^I4ungM?aMvx#ib~jGov&@Lew8TIIgvYW(>}eRs<(KVD8|{751GGhnNL{gl7(ZS`{2WcnQqX_SdSdhPFzt)L#MJKbMBdi&I~S4)0sw(=yogIqGb?Tzrq_BxW z09ZeMXuFIS*a~U2)B^>X8~ngRhQ{xca;QT8vucNWQKN2hn+fEC*EuFV+BCqd@74yQ_I$iq9ki}|UT z5-^y6W27Y}iX$MR_pcRV|5=K~Y1AeCS1eH(Zg<0cxpvRGk87~;g2^Qc3cw-_YDs@Z zvkwmg_8pIz*8l|i`1z^rE~$;bvSrfD4qsih{m;`^t~5b{1L8Sgm29%_{cvKj0MragPT+SHx)A6xpTRApfiAsNnQG4QUjHkXUy~GsK2IM z1-wf3{Nl|A1x_pa$Q(G4WRJ+uAYIdPZVCZ=1`t($hY?C3$lBW%!7w^){|>|4JX2U+ zx;$lJ;c1R$_Jm@s_py#fFf8C}tNC6B^03Nx${>9&SFMPSh-q!R0x>`tx8O~H5F>zG z5i8`x?f6R@PDUVI2Lp&UXlzTw+cJZjNhRbMG|}Mq9|kfyIvRAH_ce$c$dNv#rPd?u z87j$$e@Z=FdaVe9Y7VCDj$qS8V3$X?)Y7Ql=L}>BzJ`c4SjY<732)XY2CRgN%0)O= z40Lqj|5B#ktE)G7dBYW=`7$B(R#^>}1b|p-$jNdPX;vV?#PEl}5bY=GPyS_WkW0pa z>Q8~*FI>2_^k|M7(VY!`q_e=7{SYcz3a-VwckjTMP5<|SV=_ugvkjzTDF{ouOlLhX z-4QuZU~~d>8w6eSL`RC((INN}tqgodGD1$vK;Rpd&qLplnXk{b7(*n9 zP-379n0Qe=hsz4(QUnG@Mk8)QYiFlA!eTo*J0W@-3V8I7Lgm8(K(B*%$7OxVwlrM$iiSF%esd zK|$8819w#id;tKipt~h@#v9 zS&ul3&b#yJ8q)KZtyPef7u%m81;^v9lGwptl_|P2MFuCkmG*G;bmV((ubc1~%Cwlk zC?Byp6Kw-xDjP;-1k+$OsEvWU0K1^w?pT9OXyW*bCBM2JPNRiloNy+hfEgJXLGiuS z(syZMG^-f(*9|{|C3qDXemWlKv8e<5n+#9U0lA(4COY}*s=n>~4nwXTl0HdAy=Dkz zQ9NdN;e72UNtKoF!6ZV$l*V)|=KH1Rk?(@O2cQKE17$uBbsR&0NM#R<3#r zY?l3guY;?g5wj+VPB62vnLuc#q^DPTggg&Bg94Aj6s*0@_q>5Xv@`HGiO1_+oIoyN zXytzryPOFN2Xk8Mx;s_?EzIv0-*Q*r>+0$(0tWyLK*t+o;2AFOg2)Gm zFavvyRj)D(Vfi6A+06-EINVX99)gm-#1mjT%ph}$73!bvPq}c^Vp?1X4$tPwSU06j z^(P=j8q!~R2Y4z1KD|6$?0Mh{Oc5-tFjmziG%QVnnv%#XkifL=t1m9gQntp)QbObw z+fGOzL6x0f+g@rl6b0HHstW4V3QuxCr$P`ZYiqaKc&<}kA|um~<|c;Ep9}~Hu>4W* z0y1zKhENZOdrBpR9aJKsap8`4(<37|S*i?WGVN33E^cl-#?8cRw-A+1?vF z`V7$olHD;n{6kRZJnkKV&;~85fBsCDeLTq3Wv5JFWDa$_&S!ZIMqms(jhLckW1fiT z08ZrU#)dkz(!O6uBuBBwo+Ie=mw+D6W;%@;{V!%2SNy|F_9o~Wmp76J!3qG>?HaQA z*ww2f*5z}CY!%T8-Aj7a&LM2NrK^W~D`ZquozJ>OTEJD*Xt8HjMPHYflcWDPffd3I zXy#$tPLK-MB?pVP!`5lEJQLd4+1X!@Kbit`x_a|L(74y(tk++sxC5MG+*@E8m^;^=n)&l9NBcVq@g7MbG%DK>HWMB5p1XNvo@029iQdD;hI5_e2kS9x9xZAd7!k zmRcOmtgI-(JM1L=pd|rx;I$CgHpKUVwPIv^1=)QP3Vni)swkiWkcEK~(2r6pN36xAg9a9$lRc(PwM6I*#F(4uBBDB>k8W* zp0lO;@S&WdA_-EAnVK4hK>*+<%c5>d9b8fwReydOGpBN!&N#zSID^ep-Hn7#_F4f?fF#|Sy$ ztE+{<+rbza(J?8;AR2dLY3OQTlLT}IH6I|&WmS*C*xWH35sbOlZg42!?0HC9%1n93 zf2r8)#M`*I(dDX)#l=Nt7M5fv2^AG_=V-D(WdcOGeYeO~4@~hCDNQH9i^HFfw$gu# zv7U*2Pfz9?xYeOhC$f;=0vJAPn4zt9K}D7~LW#C>kvI73SJjc~7u300`T9XLBJUx5 zPxSov@*@IU;GatA=um(>g32Gz&@&_?XnuacyWO5#-MdhqQG{{`wB{b>K!rD^j=HI- zpY77~)oNi0Ik^mfd|E=nbJ~MB>0Hl`Gc%^QSy(cG*5~EnA=MxkIXP2+!cgi2lkf~F zDHAJekiS0>q<|KrW&u@08k%L7GCwHkS+}Ru*3vvzbz5X<)cx-TVjM6{>;A+3Q;6{Z zfVjKssu;sB4smt<{CTjMjEV=ISXwsr_5!8y0Vf2wQ~%-S<|g{qEq^eiT)p;;tQBap z!(Y!mfudX&KwQDl5@JsQTe0vGidAGcs0|vhY#tknH#jI7S}Jq@ zwKO>?2`dLky1l!rzX!Fc1}HZ#E)K;RNSC~bYlitUKqsJR>8o$@e|P^?Iiy|9S{JT& z)I#f3P1alCcd)k=8X4K56FBWVq~WpWs;c^KIBo10c=SJJ3So1~6fus*l>)auxbGc{ zg?cS}|9m++&gfB{)Ob5}m4qAUo4SA8d&@XXUY^o(qFhW6SC^7D7}9^zonidx*_WjI zf$DxJqO)g{%FC~zq*CI4@tB6`4*`9#YZmgyE2(W7Rb^ znR$6>d3hv@5?L=(oyo7Z4)?d)+r$>Dw7t zPe#TjEB1?7?*Isaed>DX^`-DSJ!&jW$ObM$=7^|zq`Jw|2c{ZSGNGuoc&Rt#%{U+! z7%Ku;d0_BMID#O`_G9MI9 Rz;Aj`viB9G@+1ts{|g9<@wxy2 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/polybezier/cfbfbbc56365ba547dc7e82b329c4007.png b/docs/images/chapters/polybezier/cfbfbbc56365ba547dc7e82b329c4007.png new file mode 100644 index 0000000000000000000000000000000000000000..3d02bdbb63809602d16d4ea973c8903bb7171b0d GIT binary patch literal 11568 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 literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html index 42983cc4..83ef8e1f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1990,27 +1990,67 @@ for p = 1 to points.length-3 (inclusive):

Unless you want sharp corners, of course. Then you don't even need 2.

We'll cover three forms of poly-Bézier curves in this section. First, we'll look at the kind that just follows point 1. where the end point of a segment is the same point as the start point of the next segment. This leads to poly-Béziers that are pretty hard to work with, but they're the easiest to implement:

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + +

Dragging the control points around only affects the curve segments that the control point belongs to, and moving an on-curve point leaves the control points where they are, which is not the most useful for practical modelling purposes. So, let's add in the logic we need to make things a little better. We'll start by linking up control points by ensuring that the "incoming" derivative at an on-curve point is the same as it's "outgoing" derivative:

- +

We can effect this quite easily, because we know that the vector from a curve's last control point to its last on-curve point is equal to the derivative vector. If we want to ensure that the first control point of the next curve matches that, all we have to do is mirror that last control point through the last on-curve point. And mirroring any point A through any point B is really simple:

- +

So let's implement that and see what it gets us. The following two graphics show a quadratic and a cubic poly-Bézier curve again, but this time moving the control points around moves others, too. However, you might see something unexpected going on for quadratic curves...

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + + -

As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point's positions is different depending on whether it's the reflection of its left or right neighbouring control point: we can't even form a proper rule-conforming curve! This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little.

+

As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point cannot satisfy the constraint that it's the reflection of its two neighbouring control points... This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little.

So: let's relax the requirement a little.

We can change the constraint so that we still preserve the angle of the derivatives across sections (so transitions from one section to the next will still look natural), but give up the requirement that they should also have the same vector length. Doing so will give us a much more useful kind of poly-Bézier curve:

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + +

Cubic curves are now better behaved when it comes to dragging control points around, but the quadratic poly-Bézier still has the problem that moving one control points will move the control points and may ending up defining "the next" control point in a way that doesn't work. Quadratic curves really aren't very useful to work with...

Finally, we also want to make sure that moving the on-curve coordinates preserves the relative positions of the associated control points. With that, we get to the kind of curve control that you might be familiar with from applications like Photoshop, Inkscape, Blender, etc.

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + + >

Again, we see that cubic curves are now rather nice to work with, but quadratic curves have a new, very serious problem: we can move an on-curve point in such a way that we can't compute what needs to "happen next". Move the top point down, below the left and right points, for instance. There is no way to preserve correct control points without a kink at the bottom point. Quadratic curves: just not that good...

A final improvement is to offer fine-level control over which points behave which, so that you can have "kinks" or individually controlled segments when you need them, with nicely well-behaved curves for the rest of the path. Implementing that, is left as an exercise for the reader.

diff --git a/docs/ja-JP/index.html b/docs/ja-JP/index.html index 0a7dae7e..d57f26c8 100644 --- a/docs/ja-JP/index.html +++ b/docs/ja-JP/index.html @@ -1986,27 +1986,67 @@ for p = 1 to points.length-3 (inclusive):

Unless you want sharp corners, of course. Then you don't even need 2.

We'll cover three forms of poly-Bézier curves in this section. First, we'll look at the kind that just follows point 1. where the end point of a segment is the same point as the start point of the next segment. This leads to poly-Béziers that are pretty hard to work with, but they're the easiest to implement:

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + +

Dragging the control points around only affects the curve segments that the control point belongs to, and moving an on-curve point leaves the control points where they are, which is not the most useful for practical modelling purposes. So, let's add in the logic we need to make things a little better. We'll start by linking up control points by ensuring that the "incoming" derivative at an on-curve point is the same as it's "outgoing" derivative:

- +

We can effect this quite easily, because we know that the vector from a curve's last control point to its last on-curve point is equal to the derivative vector. If we want to ensure that the first control point of the next curve matches that, all we have to do is mirror that last control point through the last on-curve point. And mirroring any point A through any point B is really simple:

- +

So let's implement that and see what it gets us. The following two graphics show a quadratic and a cubic poly-Bézier curve again, but this time moving the control points around moves others, too. However, you might see something unexpected going on for quadratic curves...

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + + -

As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point's positions is different depending on whether it's the reflection of its left or right neighbouring control point: we can't even form a proper rule-conforming curve! This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little.

+

As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point cannot satisfy the constraint that it's the reflection of its two neighbouring control points... This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little.

So: let's relax the requirement a little.

We can change the constraint so that we still preserve the angle of the derivatives across sections (so transitions from one section to the next will still look natural), but give up the requirement that they should also have the same vector length. Doing so will give us a much more useful kind of poly-Bézier curve:

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + +

Cubic curves are now better behaved when it comes to dragging control points around, but the quadratic poly-Bézier still has the problem that moving one control points will move the control points and may ending up defining "the next" control point in a way that doesn't work. Quadratic curves really aren't very useful to work with...

Finally, we also want to make sure that moving the on-curve coordinates preserves the relative positions of the associated control points. With that, we get to the kind of curve control that you might be familiar with from applications like Photoshop, Inkscape, Blender, etc.

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + + >

Again, we see that cubic curves are now rather nice to work with, but quadratic curves have a new, very serious problem: we can move an on-curve point in such a way that we can't compute what needs to "happen next". Move the top point down, below the left and right points, for instance. There is no way to preserve correct control points without a kink at the bottom point. Quadratic curves: just not that good...

A final improvement is to offer fine-level control over which points behave which, so that you can have "kinks" or individually controlled segments when you need them, with nicely well-behaved curves for the rest of the path. Implementing that, is left as an exercise for the reader.

diff --git a/docs/js/custom-element/api/graphics-api.js b/docs/js/custom-element/api/graphics-api.js index 6853145e..8fa69e0e 100644 --- a/docs/js/custom-element/api/graphics-api.js +++ b/docs/js/custom-element/api/graphics-api.js @@ -97,6 +97,8 @@ class GraphicsAPI extends BaseAPI { d = new Vector(p).dist(this.cursor); if (d <= cdist) { this.currentPoint = p; + this.currentPoint.mark = { x: p.x, y: p.y }; + this.currentPoint.last = { x: p.x, y: p.y }; break; } } @@ -105,8 +107,20 @@ class GraphicsAPI extends BaseAPI { onMouseMove(evt) { super.onMouseMove(evt); if (this.currentPoint) { + this.currentPoint.last = { + x: this.currentPoint.x, + y: this.currentPoint.y, + }; this.currentPoint.x = this.cursor.x; this.currentPoint.y = this.cursor.y; + this.currentPoint.diff = { + x: this.cursor.x - this.currentPoint.last.x, + y: this.cursor.y - this.currentPoint.last.y, + total: { + x: this.cursor.x - this.currentPoint.mark.x, + y: this.cursor.y - this.currentPoint.mark.y, + }, + }; } else { for (let i = 0, e = this.movable.length, p; i < e; i++) { p = this.movable[i]; @@ -121,6 +135,9 @@ class GraphicsAPI extends BaseAPI { onMouseUp(evt) { super.onMouseUp(evt); + delete this.currentPoint.mark; + delete this.currentPoint.last; + delete this.currentPoint.diff; this.currentPoint = false; } diff --git a/docs/js/custom-element/api/types/bezier.js b/docs/js/custom-element/api/types/bezier.js index 4ffc1dc4..3b6c75bb 100644 --- a/docs/js/custom-element/api/types/bezier.js +++ b/docs/js/custom-element/api/types/bezier.js @@ -92,7 +92,15 @@ class Bezier extends Original { } drawPoints(labels = true) { - const colors = [`red`, `green`, `blue`, `yellow`]; + const colors = [ + `red`, + `green`, + `blue`, + `yellow`, + `orange`, + `cyan`, + `magenta`, + ]; const api = this.api; const ctx = this.ctx; diff --git a/docs/js/custom-element/api/types/matrix.js b/docs/js/custom-element/api/types/matrix.js index cc1e9963..cca93d33 100644 --- a/docs/js/custom-element/api/types/matrix.js +++ b/docs/js/custom-element/api/types/matrix.js @@ -1,11 +1,11 @@ -// Copied from http://blog.acipo.com/matrix-inversion-in-javascript/ - function invert(M) { - // I use Guassian Elimination to calculate the inverse: + // Copied from http://blog.acipo.com/matrix-inversion-in-javascript/ + // With permission, http://blog.acipo.com/matrix-inversion-in-javascript/#comment-5057289889 + // (1) 'augment' the matrix (left) by the identity (on the right) // (2) Turn the matrix on the left into the identity by elemetry row ops // (3) The matrix on the right is the inverse (was the identity matrix) - // There are 3 elemtary row ops: (I combine b and c in my code) + // There are 3 elemtary row ops: // (a) Swap 2 rows // (b) Multiply a row by a scalar // (c) Add 2 rows diff --git a/docs/zh-CN/index.html b/docs/zh-CN/index.html index a8d82090..28e8a087 100644 --- a/docs/zh-CN/index.html +++ b/docs/zh-CN/index.html @@ -1980,27 +1980,67 @@ for p = 1 to points.length-3 (inclusive):

Unless you want sharp corners, of course. Then you don't even need 2.

We'll cover three forms of poly-Bézier curves in this section. First, we'll look at the kind that just follows point 1. where the end point of a segment is the same point as the start point of the next segment. This leads to poly-Béziers that are pretty hard to work with, but they're the easiest to implement:

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + +

Dragging the control points around only affects the curve segments that the control point belongs to, and moving an on-curve point leaves the control points where they are, which is not the most useful for practical modelling purposes. So, let's add in the logic we need to make things a little better. We'll start by linking up control points by ensuring that the "incoming" derivative at an on-curve point is the same as it's "outgoing" derivative:

- +

We can effect this quite easily, because we know that the vector from a curve's last control point to its last on-curve point is equal to the derivative vector. If we want to ensure that the first control point of the next curve matches that, all we have to do is mirror that last control point through the last on-curve point. And mirroring any point A through any point B is really simple:

- +

So let's implement that and see what it gets us. The following two graphics show a quadratic and a cubic poly-Bézier curve again, but this time moving the control points around moves others, too. However, you might see something unexpected going on for quadratic curves...

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + + -

As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point's positions is different depending on whether it's the reflection of its left or right neighbouring control point: we can't even form a proper rule-conforming curve! This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little.

+

As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all the control points are effectively linked. Move one of them, and you move all of them. Not only that, but if we move the on-curve points, it's possible to get a situation where a control point cannot satisfy the constraint that it's the reflection of its two neighbouring control points... This means that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes. And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact that the derivatives are linked means we can't manipulate curves as well as we might if we relaxed the constraints a little.

So: let's relax the requirement a little.

We can change the constraint so that we still preserve the angle of the derivatives across sections (so transitions from one section to the next will still look natural), but give up the requirement that they should also have the same vector length. Doing so will give us a much more useful kind of poly-Bézier curve:

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + +

Cubic curves are now better behaved when it comes to dragging control points around, but the quadratic poly-Bézier still has the problem that moving one control points will move the control points and may ending up defining "the next" control point in a way that doesn't work. Quadratic curves really aren't very useful to work with...

Finally, we also want to make sure that moving the on-curve coordinates preserves the relative positions of the associated control points. With that, we get to the kind of curve control that you might be familiar with from applications like Photoshop, Inkscape, Blender, etc.

- - + + + Scripts are disabled. Showing fallback image. + + + + + + Scripts are disabled. Showing fallback image. + + + >

Again, we see that cubic curves are now rather nice to work with, but quadratic curves have a new, very serious problem: we can move an on-curve point in such a way that we can't compute what needs to "happen next". Move the top point down, below the left and right points, for instance. There is no way to preserve correct control points without a kink at the bottom point. Quadratic curves: just not that good...

A final improvement is to offer fine-level control over which points behave which, so that you can have "kinks" or individually controlled segments when you need them, with nicely well-behaved curves for the rest of the path. Implementing that, is left as an exercise for the reader.