1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-12 11:44:22 +02:00

fix preloader

This commit is contained in:
Pomax
2016-01-05 02:14:32 -08:00
parent 76fc269b07
commit 1e14b594b4
2 changed files with 376 additions and 325 deletions

View File

@@ -25051,15 +25051,19 @@
null,
"We could naively implement the basis function as a mathematical construct, using the function as our guide, like this:"
),
"<pre>function Bezier(n,t):",
'\n',
" sum = 0",
'\n',
" for(k=0; k<n; k++):",
'\n',
" sum += n!/(k!*(n-k)!) * (1-t)^(n-k) * t^(k)",
'\n',
" return sum</pre>",
React.createElement(
"pre",
null,
"function Bezier(n,t):",
'\n',
" sum = 0",
'\n',
" for(k=0; k<n; k++):",
'\n',
" sum += n!/(k!*(n-k)!) * (1-t)^(n-k) * t^(k)",
'\n',
" return sum"
),
React.createElement(
"p",
null,
@@ -25076,83 +25080,95 @@
null,
"We can generate this as a list of lists lightning fast, and then never have to compute the binomial terms because we have a lookup table:"
),
"<pre>lut = [ [1], // n=0",
'\n',
" [1,1], // n=1",
'\n',
" [1,2,1], // n=2",
'\n',
" [1,3,3,1], // n=3",
'\n',
" [1,4,6,4,1], // n=4",
'\n',
" [1,5,10,10,5,1], // n=5",
'\n',
" [1,6,15,20,15,6,1]] // n=6",
'\n',
'\n',
"binomial(n,k):",
'\n',
" while(n &gt;= lut.length):",
'\n',
" s = lut.length",
'\n',
" nextRow = new array(size=s+1)",
'\n',
" nextRow[0] = 1",
'\n',
" for(i=1, prev=s-1; i&ltprev; i++):",
'\n',
" nextRow[i] = lut[prev][i-1] + lut[prev][i]",
'\n',
" nextRow[s] = 1",
'\n',
" lut.add(nextRow)",
'\n',
" return lut[n][k]</pre>",
React.createElement(
"pre",
null,
"lut = [ [1], // n=0",
'\n',
" [1,1], // n=1",
'\n',
" [1,2,1], // n=2",
'\n',
" [1,3,3,1], // n=3",
'\n',
" [1,4,6,4,1], // n=4",
'\n',
" [1,5,10,10,5,1], // n=5",
'\n',
" [1,6,15,20,15,6,1]] // n=6",
'\n',
'\n',
"binomial(n,k):",
'\n',
" while(n &gt;= lut.length):",
'\n',
" s = lut.length",
'\n',
" nextRow = new array(size=s+1)",
'\n',
" nextRow[0] = 1",
'\n',
" for(i=1, prev=s-1; i&ltprev; i++):",
'\n',
" nextRow[i] = lut[prev][i-1] + lut[prev][i]",
'\n',
" nextRow[s] = 1",
'\n',
" lut.add(nextRow)",
'\n',
" return lut[n][k]"
),
React.createElement(
"p",
null,
"So what's going on here? First, we declare a lookup table with a size that's reasonably large enough to accommodate most lookups. Then, we declare a function to get us the values we need, and we make sure that if an n/k pair is requested that isn't in the LUT yet, we expand it first. Our basis function now looks like this:"
),
"<pre>function Bezier(n,t):",
'\n',
" sum = 0",
'\n',
" for(k=0; k<n; k++):",
'\n',
" sum += binomial(n,k) * (1-t)^(n-k) * t^(k)",
'\n',
" return sum</pre>",
React.createElement(
"pre",
null,
"function Bezier(n,t):",
'\n',
" sum = 0",
'\n',
" for(k=0; k<n; k++):",
'\n',
" sum += binomial(n,k) * (1-t)^(n-k) * t^(k)",
'\n',
" return sum"
),
React.createElement(
"p",
null,
"Perfect. Of course, we can optimize further. For most computer graphics purposes, we don't need arbitrary curves. We need quadratic and cubic curves (this primer actually does do arbitrary curves, so you'll find code similar to shown here), which means we can drastically simplify the code:"
),
"<pre>function Bezier(2,t):",
'\n',
" t2 = t * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" return mt2 + 2*mt*t + t2",
'\n',
'\n',
"function Bezier(3,t):",
'\n',
" t2 = t * t",
'\n',
" t3 = t2 * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" mt3 = mt2 * mt",
'\n',
" return mt3 + 3*mt2*t + 3*mt*t2 + t3</pre>",
React.createElement(
"pre",
null,
"function Bezier(2,t):",
'\n',
" t2 = t * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" return mt2 + 2*mt*t + t2",
'\n',
'\n',
"function Bezier(3,t):",
'\n',
" t2 = t * t",
'\n',
" t3 = t2 * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" mt3 = mt2 * mt",
'\n',
" return mt3 + 3*mt2*t + 3*mt*t2 + t3"
),
React.createElement(
"p",
null,
@@ -25498,44 +25514,52 @@
null,
"Given that we already know how to implement basis function, adding in the control points is remarkably easy:"
),
"<pre>function Bezier(n,t,w[]):",
'\n',
" sum = 0",
'\n',
" for(k=0; k<n; k++):",
'\n',
" sum += w[k] * binomial(n,k) * (1-t)^(n-k) * t^(k)",
'\n',
" return sum</pre>",
React.createElement(
"pre",
null,
"function Bezier(n,t,w[]):",
'\n',
" sum = 0",
'\n',
" for(k=0; k<n; k++):",
'\n',
" sum += w[k] * binomial(n,k) * (1-t)^(n-k) * t^(k)",
'\n',
" return sum"
),
React.createElement(
"p",
null,
"And for the extremely optimized versions:"
),
"<pre>function Bezier(2,t,w[]):",
'\n',
" t2 = t * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" return w[0]*mt2 + w[1]*2*mt*t + w[2]*t2",
'\n',
'\n',
"function Bezier(3,t,w[]):",
'\n',
" t2 = t * t",
'\n',
" t3 = t2 * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" mt3 = mt2 * mt",
'\n',
" return w[0]*mt3 + 3*w[1]*mt2*t + 3*w[2]*mt*t2 + w[3]*t3</pre>",
React.createElement(
"pre",
null,
"function Bezier(2,t,w[]):",
'\n',
" t2 = t * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" return w[0]*mt2 + w[1]*2*mt*t + w[2]*t2",
'\n',
'\n',
"function Bezier(3,t,w[]):",
'\n',
" t2 = t * t",
'\n',
" t3 = t2 * t",
'\n',
" mt = 1-t",
'\n',
" mt2 = mt * mt",
'\n',
" mt3 = mt2 * mt",
'\n',
" return w[0]*mt3 + 3*w[1]*mt2*t + 3*w[2]*mt*t2 + w[3]*t3"
),
React.createElement(
"p",
null,
@@ -25956,21 +25980,25 @@
null,
"Let's just use the algorithm we just specified, and implement that:"
),
"<pre>function drawCurve(points[], t):",
'\n',
" if(points.length==1):",
'\n',
" draw(points[0])",
'\n',
" else:",
'\n',
" newpoints=array(points.size-1)",
'\n',
" for(i=0; i<newpoints.length; i++):",
'\n',
" newpoints[i] = (1-t) * points[i] + t * points[i+1]",
'\n',
" drawCurve(newpoints, t)</pre>",
React.createElement(
"pre",
null,
"function drawCurve(points[], t):",
'\n',
" if(points.length==1):",
'\n',
" draw(points[0])",
'\n',
" else:",
'\n',
" newpoints=array(points.size-1)",
'\n',
" for(i=0; i<newpoints.length; i++):",
'\n',
" newpoints[i] = (1-t) * points[i] + t * points[i+1]",
'\n',
" drawCurve(newpoints, t)"
),
React.createElement(
"p",
null,
@@ -25988,25 +26016,29 @@
),
" values:"
),
"<pre>function drawCurve(points[], t):",
'\n',
" if(points.length==1):",
'\n',
" draw(points[0])",
'\n',
" else:",
'\n',
" newpoints=array(points.size-1)",
'\n',
" for(i=0; i<newpoints.length; i++):",
'\n',
" x = (1-t) * points[i].x + t * points[i+1].x",
'\n',
" y = (1-t) * points[i].y + t * points[i+1].y",
'\n',
" newpoints[i] = new point(x,y)",
'\n',
" drawCurve(newpoints, t)</pre>",
React.createElement(
"pre",
null,
"function drawCurve(points[], t):",
'\n',
" if(points.length==1):",
'\n',
" draw(points[0])",
'\n',
" else:",
'\n',
" newpoints=array(points.size-1)",
'\n',
" for(i=0; i<newpoints.length; i++):",
'\n',
" x = (1-t) * points[i].x + t * points[i+1].x",
'\n',
" y = (1-t) * points[i].y + t * points[i+1].y",
'\n',
" newpoints[i] = new point(x,y)",
'\n',
" drawCurve(newpoints, t)"
),
React.createElement(
"p",
null,
@@ -26132,37 +26164,45 @@
null,
"Let's just use the algorithm we just specified, and implement that:"
),
"<pre>function flattenCurve(curve, segmentCount):",
'\n',
" step = 1/segmentCount;",
'\n',
" coordinates = [curve.getXValue(0), curve.getYValue(0)]",
'\n',
" for(i=1; i <= segmentCount; i++):",
'\n',
" t = i*step;",
'\n',
" coordinates.push[curve.getXValue(t), curve.getYValue(t)]",
'\n',
" return coordinates;</pre>",
React.createElement(
"pre",
null,
"function flattenCurve(curve, segmentCount):",
'\n',
" step = 1/segmentCount;",
'\n',
" coordinates = [curve.getXValue(0), curve.getYValue(0)]",
'\n',
" for(i=1; i <= segmentCount; i++):",
'\n',
" t = i*step;",
'\n',
" coordinates.push[curve.getXValue(t), curve.getYValue(t)]",
'\n',
" return coordinates;"
),
React.createElement(
"p",
null,
"And done, that's the algorithm implemented. That just leaves drawing the resulting \"curve\" as a sequence of lines:"
),
"<pre>function drawFlattenedCurve(curve, segmentCount):",
'\n',
" coordinates = flattenCurve(curve, segmentCount)",
'\n',
" coord = coordinates[0], _coords;",
'\n',
" for(i=1; i < coordinates.length; i++):",
'\n',
" _coords = coordinates[i]",
'\n',
" line(coords, _coords)",
'\n',
" coords = _coords</pre>",
React.createElement(
"pre",
null,
"function drawFlattenedCurve(curve, segmentCount):",
'\n',
" coordinates = flattenCurve(curve, segmentCount)",
'\n',
" coord = coordinates[0], _coords;",
'\n',
" for(i=1; i < coordinates.length; i++):",
'\n',
" _coords = coordinates[i]",
'\n',
" line(coords, _coords)",
'\n',
" coords = _coords"
),
React.createElement(
"p",
null,
@@ -26328,37 +26368,41 @@
null,
"We can implement curve splitting by bolting some extra logging onto the de Casteljau function:"
),
"<pre>left=[]",
'\n',
"right=[]",
'\n',
"function drawCurve(points[], t):",
'\n',
" if(points.length==1):",
'\n',
" left.add(points[0])",
'\n',
" right.add(points[0])",
'\n',
" draw(points[0])",
'\n',
" else:",
'\n',
" newpoints=array(points.size-1)",
'\n',
" for(i=0; i<newpoints.length; i++):",
'\n',
" if(i==0):",
'\n',
" left.add(points[i])",
'\n',
" if(i==newpoints.length-1):",
'\n',
" right.add(points[i+1])",
'\n',
" newpoints[i] = (1-t) * points[i] + t * points[i+1]",
'\n',
" drawCurve(newpoints, t)</pre>",
React.createElement(
"pre",
null,
"left=[]",
'\n',
"right=[]",
'\n',
"function drawCurve(points[], t):",
'\n',
" if(points.length==1):",
'\n',
" left.add(points[0])",
'\n',
" right.add(points[0])",
'\n',
" draw(points[0])",
'\n',
" else:",
'\n',
" newpoints=array(points.size-1)",
'\n',
" for(i=0; i<newpoints.length; i++):",
'\n',
" if(i==0):",
'\n',
" left.add(points[i])",
'\n',
" if(i==newpoints.length-1):",
'\n',
" right.add(points[i+1])",
'\n',
" newpoints[i] = (1-t) * points[i] + t * points[i+1]",
'\n',
" drawCurve(newpoints, t)"
),
React.createElement(
"p",
null,
@@ -28110,130 +28154,132 @@
React.createElement(
"div",
{ className: "note" },
"<pre>",
'\n',
"// A helper function to filter for values in the [0,1] interval:",
'\n',
"function accept(t) ",
'{',
'\n',
" return 0<=t && t <=1;",
'\n',
'}',
'\n',
'\n',
"// A special cuberoot function, which we can use because we don't care about complex roots:",
'\n',
"function crt(v) ",
'{',
'\n',
" if(v<0) return -Math.pow(-v,1/3);",
'\n',
" return Math.pow(v,1/3);",
'\n',
'}',
'\n',
'\n',
"// Now then: given cubic coordinates pa, pb, pc, pd, find all roots.",
'\n',
"function getCubicRoots(pa, pb, pc, pd) ",
'{',
'\n',
" var d = (-pa + 3*pb - 3*pc + pd),",
'\n',
" a = (3*pa - 6*pb + 3*pc) / d,",
'\n',
" b = (-3*pa + 3*pb) / d,",
'\n',
" c = pa / d;",
'\n',
'\n',
" var p = (3*b - a*a)/3,",
'\n',
" p3 = p/3,",
'\n',
" q = (2*a*a*a - 9*a*b + 27*c)/27,",
'\n',
" q2 = q/2,",
'\n',
" discriminant = q2*q2 + p3*p3*p3;",
'\n',
'\n',
" // and some variables we're going to use later on:",
'\n',
" var u1,v1,root1,root2,root3;",
'\n',
'\n',
" // three possible real roots:",
'\n',
" if (discriminant < 0) ",
'{',
'\n',
" var mp3 = -p/3,",
'\n',
" mp33 = mp3*mp3*mp3,",
'\n',
" r = sqrt( mp33 ),",
'\n',
" t = -q / (2*r),",
'\n',
" cosphi = t<-1 ? -1 : t>1 ? 1 : t,",
'\n',
" phi = acos(cosphi),",
'\n',
" crtr = cuberoot(r),",
'\n',
" t1 = 2*crtr;",
'\n',
" root1 = t1 * cos(phi/3) - a/3;",
'\n',
" root2 = t1 * cos((phi+2*pi)/3) - a/3;",
'\n',
" root3 = t1 * cos((phi+4*pi)/3) - a/3;",
'\n',
" return [root1, root2, root3].filter(accept);",
'\n',
" ",
'}',
'\n',
'\n',
" // three real roots, but two of them are equal:",
'\n',
" else if(discriminant === 0) ",
'{',
'\n',
" u1 = q2 < 0 ? cuberoot(-q2) : -cuberoot(q2);",
'\n',
" root1 = 2*u1 - a/3;",
'\n',
" root2 = -u1 - a/3;",
'\n',
" return [root1, root2].filter(accept);",
'\n',
" ",
'}',
'\n',
'\n',
" // one real root, two complex roots",
'\n',
" else ",
'{',
'\n',
" var sd = sqrt(discriminant);",
'\n',
" u1 = cuberoot(sd - q2);",
'\n',
" v1 = cuberoot(sd + q2);",
'\n',
" root1 = u1 - v1 - a/3;",
'\n',
" return [root1].filter(accept);",
'\n',
" ",
'}',
'\n',
'}',
"</pre>"
React.createElement(
"pre",
null,
'\n',
"// A helper function to filter for values in the [0,1] interval:",
'\n',
"function accept(t) ",
'{',
'\n',
" return 0<=t && t <=1;",
'\n',
'}',
'\n',
'\n',
"// A special cuberoot function, which we can use because we don't care about complex roots:",
'\n',
"function crt(v) ",
'{',
'\n',
" if(v<0) return -Math.pow(-v,1/3);",
'\n',
" return Math.pow(v,1/3);",
'\n',
'}',
'\n',
'\n',
"// Now then: given cubic coordinates pa, pb, pc, pd, find all roots.",
'\n',
"function getCubicRoots(pa, pb, pc, pd) ",
'{',
'\n',
" var d = (-pa + 3*pb - 3*pc + pd),",
'\n',
" a = (3*pa - 6*pb + 3*pc) / d,",
'\n',
" b = (-3*pa + 3*pb) / d,",
'\n',
" c = pa / d;",
'\n',
'\n',
" var p = (3*b - a*a)/3,",
'\n',
" p3 = p/3,",
'\n',
" q = (2*a*a*a - 9*a*b + 27*c)/27,",
'\n',
" q2 = q/2,",
'\n',
" discriminant = q2*q2 + p3*p3*p3;",
'\n',
'\n',
" // and some variables we're going to use later on:",
'\n',
" var u1,v1,root1,root2,root3;",
'\n',
'\n',
" // three possible real roots:",
'\n',
" if (discriminant < 0) ",
'{',
'\n',
" var mp3 = -p/3,",
'\n',
" mp33 = mp3*mp3*mp3,",
'\n',
" r = sqrt( mp33 ),",
'\n',
" t = -q / (2*r),",
'\n',
" cosphi = t<-1 ? -1 : t>1 ? 1 : t,",
'\n',
" phi = acos(cosphi),",
'\n',
" crtr = cuberoot(r),",
'\n',
" t1 = 2*crtr;",
'\n',
" root1 = t1 * cos(phi/3) - a/3;",
'\n',
" root2 = t1 * cos((phi+2*pi)/3) - a/3;",
'\n',
" root3 = t1 * cos((phi+4*pi)/3) - a/3;",
'\n',
" return [root1, root2, root3].filter(accept);",
'\n',
" ",
'}',
'\n',
'\n',
" // three real roots, but two of them are equal:",
'\n',
" else if(discriminant === 0) ",
'{',
'\n',
" u1 = q2 < 0 ? cuberoot(-q2) : -cuberoot(q2);",
'\n',
" root1 = 2*u1 - a/3;",
'\n',
" root2 = -u1 - a/3;",
'\n',
" return [root1, root2].filter(accept);",
'\n',
" ",
'}',
'\n',
'\n',
" // one real root, two complex roots",
'\n',
" else ",
'{',
'\n',
" var sd = sqrt(discriminant);",
'\n',
" u1 = cuberoot(sd - q2);",
'\n',
" v1 = cuberoot(sd + q2);",
'\n',
" root1 = u1 - v1 - a/3;",
'\n',
" return [root1].filter(accept);",
'\n',
" ",
'}',
'\n',
'}'
)
),
React.createElement(
"p",

View File

@@ -1,4 +1,5 @@
var blockLoader = require("block-loader");
var options = {
start: "<pre>",
end: "</pre>",
@@ -8,12 +9,16 @@ var options = {
* <pre> elements used in JSX...
*/
process: function fixPreBlocks(pre) {
return pre
var replaced = pre
.replace(options.start,'')
.replace(options.end,'')
.replace(/&/g,'&amp;')
.replace(/</g,'&lt;')
.replace(/>/g,'&gt;')
.replace(/([{}])/g,"{'$1'}")
.replace(/\n/g,"{'\\n'}");
return options.start + replaced + options.end;
}
};
module.exports = blockLoader(options);