1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-31 03:59:58 +02:00

this rename is absolutely stupid

This commit is contained in:
Pomax
2020-08-20 13:01:32 -07:00
parent 59fdafb2c5
commit d92e370bd1
470 changed files with 22 additions and 9 deletions

View File

@@ -0,0 +1,28 @@
# So what makes a Bézier Curve?
Playing with the points for curves may have given you a feel for how Bézier curves behave, but what *are* Bézier curves, really? There are two ways to explain what a Bézier curve is, and they turn out to be the entirely equivalent, but one of them uses complicated maths, and the other uses really simple maths. So... let's start with the simple explanation:
Bézier curves are the result of [linear interpolations](https://en.wikipedia.org/wiki/Linear_interpolation). That sounds complicated but you've been doing linear interpolation since you were very young: any time you had to point at something between two other things, you've been applying linear interpolation. It's simply "picking a point between two points".
If we know the distance between those two points, and we want a new point that is, say, 20% the distance away from the first point (and thus 80% the distance away from the second point) then we can compute that really easily:
\[
Given \left (
\begin{aligned}
p_1 &= some\ point \\
p_2 &= some\ other\ point \\
distance &= (p_2 - p_1) \\
ratio &= \frac{percentage}{100} \\
\end{aligned}
\right ),\ our\ new\ point = p_1 + distance \cdot ratio
\]
So let's look at that in action: the following graphic is interactive in that you can use your up and down arrow keys to increase or decrease the interpolation ratio, to see what happens. We start with three points, which gives us two lines. Linear interpolation over those lines gives us two points, between which we can again perform linear interpolation, yielding a single point. And that point —and all points we can form in this way for all ratios taken together— form our Bézier curve:
<graphics-element title="Linear Interpolation leading to Bézier curves" width="825" height="275" src="./interpolation.js"></graphics-element>
And that brings us to the complicated maths: calculus.
While it doesn't look like that's what we've just done, we actually just drew a quadratic curve, in steps, rather than in a single go. One of the fascinating parts about Bézier curves is that they can both be described in terms of polynomial functions, as well as in terms of very simple interpolations of interpolations of [...]. That, in turn, means we can look at what these curves can do based on both "real maths" (by examining the functions, their derivatives, and all that stuff), as well as by looking at the "mechanical" composition (which tells us, for instance, that a curve will never extend beyond the points we used to construct it).
So let's start looking at Bézier curves a bit more in depth: their mathematical expressions, the properties we can derive from them, and the various things we can do to, and with, Bézier curves.

View File

@@ -0,0 +1,28 @@
# ではベジエ曲線はどうやってできるのでしょう?
ベジエ曲線がどのように動くのか、点を触ってみて感覚が摑めたかもしれません。では、実際のところベジエ曲線*とは*いったい何でしょうかこれを説明する方法は2通りありますが、どちらの説明でも行き着く先はまったく同じです。一方は複雑な数学を使うのに対し、もう一方はとても簡単です。というわけで……簡単な説明の方から始めましょう。
ベジエ曲線は、[線形補間](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E8%A3%9C%E9%96%93)の結果です。というと難しそうに聞こえますが、誰でも幼い頃から線形補間をやってきています。例えば、何か2つのものの間を指し示すときには、いつも線形補間を行っています。線形補間とは、単純に「2点の間から点を得る」ことなのです。
例えば、2点間の距離がわかっているとして、一方の点から距離の20%だけ離れたすなわち、もう一方の点から80%離れた)新しい点を求めたい場合、次のようにとても簡単に計算できます。
\[
\left (
\begin{aligned}
p_1 &= 一方の点 \\
p_2 &= もう一方の点 \\
距離 &= (p_2 - p_1) \\
比率 &= \frac{百分率}{100} \\
\end{aligned}
\right )のとき、新しい点 = p_1 + 距離 \cdot 比率
\]
では、実際に見てみましょう。下の図はインタラクティブになっています。上下キーで補間の比率が増減しますので、どうなるか確かめてみましょう。最初に3点があり、それを結んで2本の直線が引かれています。この直線の上でそれぞれ線形補間を行うと、2つの点が得られます。この2点の間でさらに線形補間を行うと、1つの点を得ることができます。そして、あらゆる比率に対して同様に点を求め、それをすべて集めると、このようにベジエ曲線ができるのです。
<graphics-element title="Linear Interpolation leading to Bézier curves" width="825" height="275" src="./interpolation.js"></graphics-element>
また、これが複雑な方の数学につながっていきます。微積分です。
いま上で行ったものとは似つかないように思えますが、実はあれは2次曲線を描いていたのです。ただし一発で描きあげるのではなく、手順を追って描いていきました。ベジエ曲線は多項式関数で表現できますが、その一方で、とても単純な補間の補間の補間の……というふうにも説明できます。これがベジエ曲線のおもしろいところです。これはまた、ベジェ曲線は「本当の数学」で見る関数を調べたり微分を調べたり、あらゆる方法でことも可能ですし、「機械的」な組み立て操作として見る例えば、ベジエ曲線は組み立てに使う点の間からは決してはみ出ないということがわかりますことも可能だということを意味しています。
それでは、もう少し詳しくベジエ曲線を見ていきましょう。数学的な表現やそこから導かれる性質、さらには、ベジエ曲線に対して/ベジエ曲線を使ってできるさまざまな内容についてです。

View File

@@ -0,0 +1,28 @@
# 什么构成了贝塞尔曲线?
操作点的移动,看看曲线的变化,可能让你感受到了贝塞尔曲线是如何表现的。但贝塞尔曲线究竟*是*什么呢?有两种方式来解释贝塞尔曲线,并且可以证明它们完全相等,但是其中一种用到了复杂的数学,另外一种比较简单。所以...我们先从简单的开始吧:
贝塞尔曲线是[线性插值](https://zh.wikipedia.org/wiki/%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC)的结果。这听起来很复杂,但你在很小的时候就做过线性插值:当你指向两个物体中的另外一个物体时,你就用到了线性插值。它就是很简单的“选出两点之间的一个点”。
如果我们知道两点之间的距离并想找出离第一个点20%间距的一个新的点(也就是离第二个点80%的间距),我们可以通过简单的计算来得到:
\[
Given \left (
\begin{aligned}
p_1 &= some\ point \\
p_2 &= some\ other\ point \\
distance &= (p_2 - p_1) \\
ratio &= \frac{percentage}{100} \\
\end{aligned}
\right ),\ our\ new\ point = p_1 + distance \cdot ratio
\]
让我们来通过实际操作看一下:下面的图形都是可交互的,因此你可以通过上下键来增加或减少插值距离,来观察图形的变化。我们从三个点构成的两条线段开始。通过对各条线段进行线性插值得到两个点,对点之间的线段再进行线性插值,产生一个新的点。最终这些点——所有的点都可以通过选取不同的距离插值产生——构成了贝塞尔曲线
<graphics-element title="Linear Interpolation leading to Bézier curves" width="825" height="275" src="./interpolation.js"></graphics-element>
这为我们引出了复杂的数学:微积分。
虽然我们刚才好像没有用到这个,我们实际上只是逐步地画了一条二次曲线,而不是一次画好。贝塞尔曲线的一个很棒的特性就是它们可以通过多项式方程表示,也可以用很简单的插值形式表示。因此,反过来说,我们可以基于“真正的数学”(检查方程式,导数之类的东西),也可以通过观察曲线的“机械”构成(比如说,可以得知曲线永远不会延伸超过我们用来构造它的点),来看看这些曲线能够做什么。
让我们从更深的层次来观察贝塞尔曲线。看看它们的数学表达式,从这些表达式衍生得到的属性,以及我们可以对贝塞尔曲线做的事。

View File

@@ -0,0 +1,141 @@
setup() {
this.step = 25;
this.curve = Bezier.defaultQuadratic(this);
setMovable(this.curve.points);
}
draw() {
resetTransform();
clear(`white`);
this.drawBasics();
this.drawPointCurve();
this.drawInterpolations();
this.drawCurveCoordinates();
}
drawBasics() {
setStroke(`black`);
setFill(`black`);
this.curve.drawSkeleton();
text(`First linear interpolation, spaced ${this.step}% (${Math.floor(99/this.step)} steps)`, {x:5, y:15});
translate(this.height, 0);
line(0, 0, 0, this.height);
this.curve.drawSkeleton();
text(`Second interpolation, between each generated pair`, {x:5, y:15});
translate(this.height, 0);
line(0, 0, 0, this.height);
this.curve.drawSkeleton();
text(`Curve points generated this way`, {x:5, y:15});
}
drawPointCurve() {
setStroke(`lightgrey`);
for(let i=1, e=50, p; i<=e; i++) {
p = this.curve.get(i/e);
circle(p.x, p.y, 1);
}
}
drawInterpolations() {
for(let i=this.step; i<100; i+=this.step) {
resetTransform();
this.setIterationColor(i);
let [np2, np3] = this.drawFirstInterpolation(this.curve.points, i);
let np4 = this.drawSecondInterpolation(np2, np3, i);
this.drawOnCurve(np4, i);
}
}
setIterationColor(i) {
let c = `#${(2*i).toString(16)}00${(255 - 2*i).toString(16)}`;
setFill(c);
setStroke(`${c}55`);
}
drawFirstInterpolation(p, i) {
p = p.map(v => new Vector(v));
let np2 = p[1].subtract(p[1].subtract(p[0]).scale(1 - i/100));
circle(np2.x, np2.y, 5);
text(`${i}%`, np2.add({x:10,y:0}));
let np3 = p[2].subtract(p[2].subtract(p[1]).scale(1 - i/100));
circle(np3.x, np3.y, 5);
text(`${i}%`, np3.add({x:-10,y:-15}));
return [np2, np3];
}
drawSecondInterpolation(np2, np3, i) {
translate(this.height, 0);
line(np2.x, np2.y, np3.x, np3.y);
circle(np2.x, np2.y, 5);
circle(np3.x, np3.y, 5);
let np4 = np3.subtract(np3.subtract(np2).scale(1 - i/100));
circle(np4.x, np4.y, 2);
text(`${i}%`, np4.add({x:10,y:10}));
return np4;
}
drawOnCurve(np4, i) {
translate(this.height, 0);
circle(np4.x, np4.y, 2);
text(`ratio = ${i/100}`, np4.add({x:10,y:15}));
}
drawCurveCoordinates() {
this.resetTransform();
this.curve.drawPoints();
translate(this.height, 0);
this.curve.drawPoints();
translate(this.height, 0);
this.curve.drawPoints();
}
onKeyDown() {
this.mark = false;
if (this.keyboard[`ArrowDown`]) {
this.stepDown();
}
if (this.keyboard[`ArrowUp`]) {
this.stepUp();
}
redraw();
}
stepDown(value = 1) {
this.step -= value;
if (this.step < 10) this.step = 10;
}
stepUp(value = 1) {
this.step += value;
if (this.step > 90) this.step = 90;
}
onMouseDown() {
this.mark = this.cursor.y;
}
onMouseUp() {
this.mark = false;
}
onMouseMove() {
if (this.mark && !this.currentPoint) {
let diff = this.mark - this.cursor.y,
mapped = map(diff, -this.height/2, this.height/2, 10, 90, true);
this.step = mapped | 0;
}
redraw();
}