diff --git a/components/sections/pointcurves/index.js b/components/sections/pointcurves/index.js index 772e1e14..ca2b3663 100644 --- a/components/sections/pointcurves/index.js +++ b/components/sections/pointcurves/index.js @@ -43,21 +43,20 @@ var PointCurves = React.createClass({ drawQuadratic: function(api, curve) { var w = api.getPanelWidth(), h = api.getPanelHeight(), - offset = {x:w, y:0}, labels = ["start","t=0.5","end"]; api.reset(); + api.setColor("lightblue"); + api.drawGrid(10,10); + api.setFill("black"); + api.setColor("black"); api.lpts.forEach((p,i) => { api.drawCircle(p,3); api.text(labels[i], p, {x:5, y:2}); }); - api.setColor("black"); - api.drawLine({x:0,y:0},{x:0,y:h}, offset); - api.drawLine({x:w,y:0},{x:w,y:h}, offset); - if(api.lpts.length === 3) { var S = api.lpts[0], E = api.lpts[2], @@ -89,20 +88,19 @@ var PointCurves = React.createClass({ drawCubic: function(api, curve) { var w = api.getPanelWidth(), h = api.getPanelHeight(), - offset = {x:w, y:0}, labels = ["start","t=0.5","end"]; api.reset(); api.setFill("black"); + api.setColor("black"); api.lpts.forEach((p,i) => { api.drawCircle(p,3); api.text(labels[i], p, {x:5, y:2}); }); - api.setColor("black"); - api.drawLine({x:0,y:0},{x:0,y:h}, offset); - api.drawLine({x:w,y:0},{x:w,y:h}, offset); + api.setColor("lightblue"); + api.drawGrid(10,10); if(api.lpts.length === 3) { var S = api.lpts[0], @@ -112,23 +110,33 @@ var PointCurves = React.createClass({ x: (S.x + E.x)/2, y: (S.y + E.y)/2, }; + api.setColor("blue"); api.drawLine(S, E); api.drawLine(B, C); api.drawCircle(C, 3); + var ratio = this.getCRatio(0.5), A = { x: B.x + (B.x-C.x)/ratio, y: B.y + (B.y-C.y)/ratio }, + selen = api.utils.dist(S,E), + bclen_min = selen/8, + bclen = api.utils.dist(B,C), + aesthetics = 4, + be12dist = bclen_min + bclen/aesthetics, + bx = be12dist * (E.x-S.x)/selen, + by = be12dist * (E.y-S.y)/selen, e1 = { - x: B.x - (E.x-S.x)/4, - y: B.y - (E.y-S.y)/4 + x: B.x - bx, + y: B.y - by }, e2 = { - x: B.x + (E.x-S.x)/4, - y: B.y + (E.y-S.y)/4 + x: B.x + bx, + y: B.y + by }, + v1 = { x: A.x + (e1.x-A.x)*2, y: A.y + (e1.y-A.y)*2 @@ -137,6 +145,7 @@ var PointCurves = React.createClass({ x: A.x + (e2.x-A.x)*2, y: A.y + (e2.y-A.y)*2 }, + nc1 = { x: S.x + (v1.x-S.x)*2, y: S.y + (v1.y-S.y)*2 @@ -144,8 +153,9 @@ var PointCurves = React.createClass({ nc2 = { x: E.x + (v2.x-E.x)*2, y: E.y + (v2.y-E.y)*2 - }, - curve = new api.Bezier([S, nc1, nc2, E]); + }; + + var curve = new api.Bezier([S, nc1, nc2, E]); api.drawLine(e1, e2); api.setColor("lightgrey"); api.drawLine(A, C); @@ -168,29 +178,39 @@ var PointCurves = React.createClass({

Given the preceding section on curve manipulation, we can also generate quadratic and cubic - curves from any three points. However, unlike circle-fitting, which requires only three points, - Bézier curve fitting requires three points, as well as a t value (so we can figure out - where point 'C' needs to be) and in cade of quadratic curves, a tangent that lets us place - those points 'e1' and 'e2' around our point 'B'.

+ curves from any three points. However, unlike circle-fitting, which requires just three points, + Bézier curve fitting requires three points, as well as a t value, so we can figure out + where point 'C' needs to be.

-

There's some freedom here, so for illustrative purposes we're going to pretend t is - simply 0.5, which puts C in the middle of the start--end line segment, and then we'll also set - the cubic curve's tangent to half the length of start--end, centered on B.

- -

Using these "default" values for curve creation, we can already get fairly respectable - curves; Click three times on each of the following sketches to set up the points - that should be used to form a quadratic and cubic curve, respectively:

+

The following graphic lets you place three points, and will use the preceding sections on the + ABC ratio and curve construction to form a quadratic curve through them. You can move the points + you've placed around by click-dragging, or try a new curve by drawing new points with pure clicks. + (There's some freedom here, so for illustrative purposes we clamped t to simply be + 0.5, lets us bypass some maths, since a t value of 0.5 always puts C in the middle of + the start--end line segment)

+ +

For cubic curves we also need some values to construct the "de Casteljau line through B" with, + and that gives us quite a bit of choice. Since we've clamped t to 0.5, we'll set up a line + through B parallel to the line start--end, with a length that is proportional to the length of the + line B--C: the further away from the baseline B is, the wider its construction line will be, and so + the more "bulby" the curve will look. This still gives us some freedom in terms of exactly how to + scale the length of the construction line as we move B closer or further away from the baseline, so + I simply picked some values that sort-of-kind-of look right in that if a circle through (start,B,end) + forms a perfect hemisphere, the cubic curve constructed forms something close to a hemisphere, too, + and if the points lie on a line, then the curve constructed has the control points very close to + B, while still lying between B and the correct curve end point:

+

In each graphic, the blue parts are the values that we "just have" simply by setting up - our three points, and deciding on which t-value (and tangent, for cubic curves) - we're working with. There are many ways to determine a combination of t and tangent - values that lead to a more "aesthetic" curve, but this will be left as an exercise to the - reader, since there are many, and aesthetics are often quite personal.

+ our three points, combined with our decision on which t value to use (and construction line + orientation and length for cubic curves). There are of course many ways to determine a combination + of t and tangent values that lead to a more "aesthetic" curve, but this will be left as an + exercise to the reader, since there are many, and aesthetics are often quite personal.

); }