From 60f24a5d1f5f6d8763f8786e82fa351cf83a832f Mon Sep 17 00:00:00 2001
From: Pomax
+
-
-[SirVer's Castle](http://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves)には、最適な次元削減で必要になる行列について(数学的ですが)良い解説があります。時間があれば、これを直接この記事の中で説明したいところです。
diff --git a/chapters/reordering/handler.js b/chapters/reordering/handler.js
deleted file mode 100644
index 0160cfd2..00000000
--- a/chapters/reordering/handler.js
+++ /dev/null
@@ -1,150 +0,0 @@
-var invert = require('../../../lib/matrix-invert.js');
-var multiply = require('../../../lib/matrix-multiply.js');
-var transpose = require('../../../lib/matrix-transpose.js');
-
-var Reordering = {
- statics: {
- keyHandlingOptions: {
- values: {
- "38": function(api) {
- api.setCurve(api.curve.raise());
- api.redraw();
- },
- "40": function(api) {
- api.setCurve(Reordering.lower(api));
- api.redraw();
- }
- }
- }
- },
-
- // Based on http://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves/
- lower: function(api) {
- var curve = api.curve,
- pts = curve.points,
- k = pts.length,
- M = [],
- n = k-1,
- i;
-
- // build M, which will be (k) rows by (k-1) columns
- for(i=0; i
W1
- <Graphic title={"A " + this.getOrder() + " order Bézier curve"} - setup={this.setup} draw={this.draw} onKeyDown={this.props.onKeyDown} - onMouseMove={this.onMouseMove} /> -
+- ベジエ曲線のおもしろい性質のひとつに、「n次の曲線は常に、n+1次の曲線で完璧に表すことができる」というものがあります。このとき、制御点は新しいものになります。 + One interesting property of Bézier curves is that an + nth order curve can always be perfectly + represented by an (n+1)th order curve, by giving + the higher-order curve specific control points.
- たとえば3点で定義される曲線があるとき、これを正確に再現するような、4点で定義される曲線を作ることができます。始点と終点はそのままにして、「1/3 - 始点 + 2/3 制御点」と「2/3 制御点 + 1/3 - 終点」を新たな2つの制御点に選べば、元の曲線と正確に一致する曲線が得られます。異なっているのは、2次ではなく3次の曲線だという点だけです。 + If we have a curve with three points, then we can create a curve + with four points that exactly reproduces the original curve. First, + we give it the same start and end points, and for its two control + points we pick "1/3rd start + 2/3rd control" + and "2/3rd control + 1/3rd end". Now we have + exactly the same curve as before, except represented as a cubic + curve rather than a quadratic curve.
- n次の曲線をn+1次の曲線へと次数上げするための一般の規則は、次のようになります(始点と終点の重みは、元の曲線のものと変わらないことがわかります)。 + The general rule for raising an nth order curve + to an (n+1)th order curve is as follows + (observing that the start and end weights are the same as the start + and end weights for the old curve):
- しかし同時にこの規則から、n次の曲線をn-1次の曲線へと次数下げすることは、一般には不可能だという結論も得られます。なぜなら、制御点をきれいに「引き離す」ことができないからです。試してみたところで、得られる曲線は元と同じにはなりません。それどころか、まったくの別物に見えるかもしれません。 -
-- 下の図では(半分)ランダムな曲線に対して、この規則を試してみることができます。図を選択して上下キーを押すと、次数上げや次数下げができます。 -
-- <Graphic title={this.state.order + "次のベジエ曲線"} - setup={this.setup} draw={this.draw} onKeyDown={this.props.onKeyDown} - /> + However, this rule also has as direct consequence that you + cannot generally safely lower a curve from + nth order to (n-1)th order, + because the control points cannot be "pulled apart" cleanly. We can + try to, but the resulting curve will not be identical to the + original, and may in fact look completely different.
+ However, there is a surprisingly good way to ensure that a lower + order curve looks "as close as reasonably possible" to the original + curve: we can optimise the "least-squares distance" between the + original curve and the lower order curve, in a single operation + (also explained over on SirVer's Castleには、最適な次元削減で必要になる行列について(数学的ですが)良い解説があります。時間があれば、これを直接この記事の中で説明したいところです。 + >Sirver's Castle). However, to use it, we'll need to do some calculus work and then + switch over to linear algebra. As mentioned in the section on matrix + representations, some things can be done much more easily with + matrices than with calculus functions, and this is one of those + things. So... let's go!
++ We start by taking the standard Bézier function, and condensing it a + little: +
+
+ Then, we apply one of those silly (actually, super useful) calculus
+ tricks: since our t
value is always between zero and
+ one (inclusive), we know that (1-t)
plus
+ t
always sums to 1. As such, we can express any value
+ as a sum of t
and 1-t
:
+
+ So, with that seemingly trivial observation, we rewrite that Bézier
+ function by splitting it up into a sum of a (1-t)
and
+ t
component:
+
+ So far so good. Now, to see why we did this, let's write out the
+ (1-t)
and t
parts, and see what that gives
+ us. I promise, it's about to make sense. We start with
+ (1-t)
:
+
+ So by using this seemingly silly trick, we can suddenly express part
+ of our nth order Bézier function in terms of an (n+1)th
+ order Bézier function. And that sounds a lot like raising the curve
+ order! Of course we need to be able to repeat that trick for the
+ t
part, but that's not a problem:
+
+ So, with both of those changed from an order
+ n
expression to an order (n+1)
expression,
+ we can put them back together again. Now, where the order
+ n
function had a summation from 0 to n
,
+ the order n+1
function uses a summation from 0 to
+ n+1
, but this shouldn't be a problem as long as we can
+ add some new terms that "contribute nothing". In the next section on
+ derivatives, there is a discussion about why "higher terms than
+ there is a binomial for" and "lower than zero terms" both
+ "contribute nothing". So as long as we can add terms that have the
+ same form as the terms we need, we can just include them in the
+ summation, they'll sit there and do nothing, and the resulting
+ function stays identical to the lower order curve.
+
Let's do this:
++ And this is where we switch over from calculus to linear algebra, + and matrices: we can now express this relation between Bézier(n,t) + and Bézier(n+1,t) as a very simple matrix multiplication: +
+
+ where the matrix M is an n+1
by
+ n
matrix, and looks like:
+
+ That might look unwieldy, but it's really just a mostly-zeroes + matrix, with a very simply fraction on the diagonal, and an even + simpler fraction to the left of it. Multiplying a list of + coordinates with this matrix means we can plug the resulting + transformed coordinates into the one-order-higher function and get + an identical looking curve. +
+Not too bad!
++ Equally interesting, though, is that with this matrix operation + established, we can now use an incredibly powerful and ridiculously + simple way to find out a "best fit" way to reverse the operation, + called + the normal equation. What it does is minimize the sum of the square differences + between one set of values and another set of values. Specifically, + if we can express that as some function A x = b, we + can use it. And as it so happens, that's exactly what we're dealing + with, so: +
+The steps taken here are:
+
+ And we're done: we now have an expression that lets us approximate
+ an n+1
th order curve with a lower
+ n
th order curve. It won't be an exact fit,
+ but it's definitely a best approximation. So, let's implement these
+ rules for raising and lowering curve order to a (semi) random curve,
+ using the following graphic. Select the sketch, which has movable
+ control points, and press your up and down arrow keys to raise or
+ lower the curve order.
+
- <Graphic title={"A " + this.getOrder() + " order Bézier curve"} - setup={this.setup} draw={this.draw} onKeyDown={this.props.onKeyDown} - onMouseMove={this.onMouseMove} /> -
+