1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-15 05:04:25 +02:00

proper div escaping during locale conversion

This commit is contained in:
Pomax
2017-02-15 14:59:24 -08:00
parent 47a803c80a
commit b47a94d23d
8 changed files with 312 additions and 188 deletions

View File

@@ -0,0 +1,75 @@
# Controlling Bézier curvatures
Bézier curves are (like all "splines") interpolation functions, meaning they take a set of points, and generate values somewhere "between" those points. (One of the consequences of this is that you'll never be able to generate a point that lies outside the outline for the control points, commonly called the "hull" for the curve. Useful information!). In fact, we can visualize how each point contributes to the value generated by the function, so we can see which points are important, where, in the curve.
The following graphs show the interpolation functions for quadratic and cubic curves, with "S" being the strength of a point's contribution to the total sum of the Bézier function. Click or click-drag to see the interpolation percentages for each curve-defining point at a specific <i>t</i> value.
<div className="figure">
<Graphic inline={true} preset="simple" title="Quadratic interpolations" draw={this.drawQuadraticLerp}/>
<Graphic inline={true} preset="simple" title="Cubic interpolations" draw={this.drawCubicLerp}/>
<Graphic inline={true} preset="simple" title="15th order interpolations" draw={this.draw15thLerp}/>
</div>
Also shown is the interpolation function for a 15<sup>th</sup> order Bézier function. As you can see, the start and end point contribute considerably more to the curve's shape than any other point in the control point set.
If we want to change the curve, we need to change the weights of each point, effectively changing the interpolations. The way to do this is about as straight forward as possible: just multiply each point with a value that changes its strength. These values are conventionally called "Weights", and we can add them to our original Bézier function:
\[
Bézier(n,t) = \sum_{i=0}^{n}
\underset{binomial\ term}{\underbrace{\binom{n}{i}}}
\cdot\
\underset{polynomial\ term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}}
\cdot\
\underset{weight}{\underbrace{w_i}}
\]
That looks complicated, but as it so happens, the "weights" are actually just the coordinate values we want our curve to have: for an <i>n<sup>th</sup></i> order curve, w<sub>0</sub> is our start coordinate, w<sub>n</sub> is our last coordinate, and everything in between is a controlling coordinate. Say we want a cubic curve that starts at (120,160), is controlled by (35,200) and (220,260) and ends at (220,40), we use this Bézier curve:
\[
\left \{ \begin{matrix}
x = BLUE[120] \cdot (1-t)^3 + BLUE[35] \cdot 3 \cdot (1-t)^2 \cdot t + BLUE[220] \cdot 3 \cdot (1-t) \cdot t^2 + BLUE[220] \cdot t^3 \\
y = BLUE[160] \cdot (1-t)^3 + BLUE[200] \cdot 3 \cdot (1-t)^2 \cdot t + BLUE[260] \cdot 3 \cdot (1-t) \cdot t^2 + BLUE[40] \cdot t^3
\end{matrix} \right.
\]
Which gives us the curve we saw at the top of the article:
<Graphic preset="simple" title="Our cubic Bézier curve" setup={this.drawCubic} draw={this.drawCurve}/>
What else can we do with Bézier curves? Quite a lot, actually. The rest of this article covers a multitude of possible operations and algorithms that we can apply, and the tasks they achieve.
<div className="howtocode">
### How to implement the weighted basis function
Given that we already know how to implement basis function, adding in the control points is remarkably easy:
```
function Bezier(n,t,w[]):
sum = 0
for(k=0; k<n; k++):
sum += w[k] * binomial(n,k) * (1-t)^(n-k) * t^(k)
return sum
```
And for the extremely optimized versions:
```
function Bezier(2,t,w[]):
t2 = t * t
mt = 1-t
mt2 = mt * mt
return w[0]*mt2 + w[1]*2*mt*t + w[2]*t2
function Bezier(3,t,w[]):
t2 = t * t
t3 = t2 * t
mt = 1-t
mt2 = mt * mt
mt3 = mt2 * mt
return w[0]*mt3 + 3*w[1]*mt2*t + 3*w[2]*mt*t2 + w[3]*t3
```
And now we know how to program the weighted basis function.
</div>

View File

@@ -1,11 +1,13 @@
var React = require("react");
var Graphic = require("../../Graphic.jsx");
var SectionHeader = require("../../SectionHeader.jsx");
var Locale = require("../../../lib/locale");
var locale = new Locale("en-GB");
var page = "control";
var Control = React.createClass({
getDefaultProps: function() {
return {
title: "Controlling Bézier curvatures"
title: locale.getTitle(page)
};
},
@@ -168,99 +170,7 @@ var Control = React.createClass({
},
render: function() {
return (
<section>
<SectionHeader {...this.props} />
<p>Bézier curves are (like all "splines") interpolation functions, meaning they take a set of
points, and generate values somewhere "between" those points. (One of the consequences of this
is that you'll never be able to generate a point that lies outside the outline for the control
points, commonly called the "hull" for the curve. Useful information!). In fact, we can visualize
how each point contributes to the value generated by the function, so we can see which points are
important, where, in the curve.</p>
<p>The following graphs show the interpolation functions for quadratic and cubic curves, with "S"
being the strength of a point's contribution to the total sum of the Bézier function. Click or
click-drag to see the interpolation percentages for each curve-defining point at a
specific <i>t</i> value.</p>
<div className="figure">
<Graphic inline={true} preset="simple" title="Quadratic interpolations" draw={this.drawQuadraticLerp}/>
<Graphic inline={true} preset="simple" title="Cubic interpolations" draw={this.drawCubicLerp}/>
<Graphic inline={true} preset="simple" title="15th order interpolations" draw={this.draw15thLerp}/>
</div>
<p>Also shown is the interpolation function for a 15<sup>th</sup> order Bézier function. As you can see,
the start and end point contribute considerably more to the curve's shape than any other point
in the control point set.</p>
<p>If we want to change the curve, we need to change the weights of each point, effectively changing
the interpolations. The way to do this is about as straight forward as possible: just multiply each
point with a value that changes its strength. These values are conventionally called "Weights", and
we can add them to our original Bézier function:</p>
<p>\[
Bézier(n,t) = \sum_{i=0}^{n}
\underset{binomial\ term}{\underbrace{\binom{n}{i}}}
\cdot\
\underset{polynomial\ term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}}
\cdot\
\underset{weight}{\underbrace{w_i}}
\]</p>
<p>That looks complicated, but as it so happens, the "weights" are actually just the coordinate values
we want our curve to have: for an <i>n<sup>th</sup></i> order curve, w<sub>0</sub> is our start coordinate,
w<sub>n</sub> is our last coordinate, and everything in between is a controlling coordinate. Say we want
a cubic curve that starts at (120,160), is controlled by (35,200) and (220,260) and ends at (220,40),
we use this Bézier curve:</p>
<p>\[
\left \{ \begin{matrix}
x = BLUE[120] \cdot (1-t)^3 + BLUE[35] \cdot 3 \cdot (1-t)^2 \cdot t + BLUE[220] \cdot 3 \cdot (1-t) \cdot t^2 + BLUE[220] \cdot t^3 \\
y = BLUE[160] \cdot (1-t)^3 + BLUE[200] \cdot 3 \cdot (1-t)^2 \cdot t + BLUE[260] \cdot 3 \cdot (1-t) \cdot t^2 + BLUE[40] \cdot t^3
\end{matrix} \right. \]</p>
<p>Which gives us the curve we saw at the top of the article:</p>
<Graphic preset="simple" title="Our cubic Bézier curve" setup={this.drawCubic} draw={this.drawCurve}/>
<p>What else can we do with Bézier curves? Quite a lot, actually. The rest of this article covers
a multitude of possible operations and algorithms that we can apply, and the tasks they achieve.</p>
<div className="howtocode">
<h3>How to implement the weighted basis function</h3>
<p>Given that we already know how to implement basis function, adding in the control points
is remarkably easy:</p>
<pre>function Bezier(n,t,w[]):
sum = 0
for(k=0; k<n; k++):
sum += w[k] * binomial(n,k) * (1-t)^(n-k) * t^(k)
return sum</pre>
<p>And for the extremely optimized versions:</p>
<pre>function Bezier(2,t,w[]):
t2 = t * t
mt = 1-t
mt2 = mt * mt
return w[0]*mt2 + w[1]*2*mt*t + w[2]*t2
function Bezier(3,t,w[]):
t2 = t * t
t3 = t2 * t
mt = 1-t
mt2 = mt * mt
mt3 = mt2 * mt
return w[0]*mt3 + 3*w[1]*mt2*t + 3*w[2]*mt*t2 + w[3]*t3</pre>
<p>And now we know how to program the weighted basis function.</p>
</div>
</section>
);
return <section>{ locale.getContent(page, this) }</section>;
}
});

View File

@@ -96,21 +96,25 @@ It's basically just a sum of "every combination of <i>a</i> and <i>b</i>", progr
And that's the full description for Bézier curves. Σ in this function indicates that this is a series of additions (using the variable listed below the Σ, starting at ...=&lt;value&gt; and ending at the value listed on top of the Σ).
<div className="howtocode">
### How to implement the basis function
We could naively implement the basis function as a mathematical construct, using the function as our guide, like this:
<pre>function Bezier(n,t):
```
function Bezier(n,t):
sum = 0
for(k=0; k<n; k++):
sum += n!/(k!*(n-k)!) * (1-t)^(n-k) * t^(k)
return sum</pre>
return sum
```
I say we could, because we're not going to: the factorial function is *incredibly* expensive. And, as we can see from the above explanation, we can actually create Pascal's triangle quite easily without it: just start at [1], then [1,1], then [1,2,1], then [1,3,3,1], and so on, with each next row fitting 1 more number than the previous row, starting and ending with "1", with all the numbers in between being the sum of the previous row's elements on either side "above" the one we're computing.
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
```
lut = [ [1], // n=0
[1,1], // n=1
[1,2,1], // n=2
[1,3,3,1], // n=3
@@ -127,19 +131,23 @@ binomial(n,k):
nextRow[i] = lut[prev][i-1] + lut[prev][i]
nextRow[s] = 1
lut.add(nextRow)
return lut[n][k]</pre>
return lut[n][k]
```
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):
```
function Bezier(n,t):
sum = 0
for(k=0; k<=n; k++):
sum += binomial(n,k) * (1-t)^(n-k) * t^(k)
return sum</pre>
return sum
```
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):
```
function Bezier(2,t):
t2 = t * t
mt = 1-t
mt2 = mt * mt
@@ -151,9 +159,11 @@ function Bezier(3,t):
mt = 1-t
mt2 = mt * mt
mt3 = mt2 * mt
return mt3 + 3*mt2*t + 3*mt*t2 + t3</pre>
return mt3 + 3*mt2*t + 3*mt*t2 + t3
```
And now we know how to program the basis function. Exellent.
</div>
So, now we know what the base function(s) look(s) like, time to add in the magic that makes Bézier curves so special: control points.

View File

@@ -30,7 +30,6 @@ If you have suggestions for new sections, hit up the [Github issue tracker](http
## Buy me a coffee?
If you enjoyed this book, or you simply found it useful for something you were trying to get done, and you were wondering how to let me know you appreciated this book, you can
always [buy me a coffee](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QPRDLNGDANJSW), however-much a coffee is where you live. This work has grown over the years, from a small primer to a 70ish print-page-equivalent reader on the subject of Bézier curves, and a lot of coffee went into the making of it. I don't regret a minute I spent on writing it, but I can always do with some more coffee to keep on writing!
If you enjoyed this book, or you simply found it useful for something you were trying to get done, and you were wondering how to let me know you appreciated this book, you can always [buy me a coffee](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QPRDLNGDANJSW), however-much a coffee is where you live. This work has grown over the years, from a small primer to a 70ish print-page-equivalent reader on the subject of Bézier curves, and a lot of coffee went into the making of it. I don't regret a minute I spent on writing it, but I can always do with some more coffee to keep on writing!
</div>

View File

@@ -7,7 +7,7 @@ var page = "whatis";
var Whatis = React.createClass({
getDefaultProps: function() {
return {
title: "So what makes a Bézier Curve?"
title: locale.getTitle(page)
};
},