@@ -3656,7 +3656,7 @@ B'(t) = a(1-t) + b(t)= 0,
you haven't, it looks like this:
@@ -3696,21 +3696,21 @@ B'(t) uses { v ,v ,v }, where v = 3(p -p ), v = 3(p -p ), v = 3(p -p )
/>
@@ -4428,7 +4428,7 @@ C(t) = 0
circle being on the other side of the curve. So what does
look like? Actually something that seems not too hard:
@@ -4457,15 +4457,15 @@ C(t) = Bézier \prime(t) · Bézier \prime\prime(t) - Bézier \prime(t)
with the first and second derivatives, given our basis functions:
@@ -4981,16 +4981,16 @@ mapped = (x) = │ 1 2
We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:
@@ -5001,7 +5001,7 @@ x(t) = (-a + 3b- 3c + d)t + (3a - 6b + 3c)t + (-3a + 3b)t + a
known constants, we can trivially rewrite this (by moving the
across the equal sign) as:
@@ -5085,7 +5085,7 @@ y = curve.get(t).y
@@ -5197,16 +5197,16 @@ length = | ⟍│(dx/dt) +(dy/dt) dt
shifting and scaling the inputs. Doing so, we get the following:
@@ -5494,7 +5494,7 @@ function kappa(t, B):
circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:
@@ -5912,22 +5912,22 @@ C = u(t) · P + (1-u(t)) · P
(with thanks to Boris Zbarsky) shows us the following two formulae:
e2 coordinates must obey the standard de Casteljau rule for linear interpolation:
@@ -6112,7 +6112,7 @@ A = B - ───────── = B + ─────────
curve with a loop in it. To do this, we can use the
function:
@@ -6129,8 +6129,8 @@ A = B - ───────── = B + ─────────
Which seems simple enough. Unfortunately, when we expand that dist
function, things get a lot more problematic:
@@ -6708,12 +6708,12 @@ A = B - ────────── = B + ──────────
form, where each line corresponds to a power of t, and each column is for a specific coefficient. First, we expand the function:
@@ -6889,10 +6889,10 @@ D = ┌ d d ... d ┐, where ╡ 1
fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:
In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:
@@ -6985,7 +6985,7 @@ E(C) = (P - TMC) (P - TMC)
those, and then use that 𝕋 instead of
in our error function:
@@ -7042,7 +7042,7 @@ E(C) = (P - 𝕋MC) (P - 𝕋MC)
taking the derivative, and determining where that derivative is zero:
@@ -7164,13 +7164,13 @@ C = M (𝕋 𝕋) 𝕋 P
previous and next point:
@@ -7951,7 +7951,7 @@ B'(1) = B'(0)
last control point through the last on-curve point. And mirroring any point A through any point B is really simple:
B(t). Easy enough:
@@ -8450,7 +8450,7 @@ b = ────────
polynomial, and we know where the circle arc's actual point P is for angle φ/2:
Wolfram Alpha is definitely the way to go. That said, let's get going:
Which also gives us the commonly found value of 0.55228 for quarter circles, based on them having an angle of half π:
@@ -9541,7 +9541,7 @@ N (t) = ╡ i i+1
P(t), we can compute this point by evaluating
@@ -9582,34 +9582,34 @@ d (t) = 0, d (t) = N (t) = ╡ i i+1
recursion diagram:
diff --git a/docs/ja-JP/index.html b/docs/ja-JP/index.html
index 2f9a514e..02148129 100644
--- a/docs/ja-JP/index.html
+++ b/docs/ja-JP/index.html
@@ -41,7 +41,7 @@
diff --git a/docs/ko-KR/index.html b/docs/ko-KR/index.html
index 4d4abe7e..8a1b0080 100644
--- a/docs/ko-KR/index.html
+++ b/docs/ko-KR/index.html
@@ -43,7 +43,7 @@
-
+
@@ -183,7 +183,7 @@
3GY1HbQ2cH9V4xBLnRYdEfc42Nd1ZyjLZu
or use the QR code on the right, if that's the kind of convenience you prefer =)
-
+
@@ -577,7 +577,7 @@
@@ -646,7 +646,7 @@ f(x) = cos (x)
여기까지는 좋습니다. 이제 매개변수 함수를 보고, 어떤 꼼수를 쓰는지 확인해 봅시다. 아래의 두 함수를 생각해 봅시다.
@@ -657,9 +657,9 @@ f(b) = sin (b)
꼼수입니다. 매개변수 함수에서는 아래와 같이 여러 가지 함수가 같은 변수를 공유합니다.
@@ -676,8 +676,8 @@ f(b) = sin (b)
매개변수 곡선을 만들 때 보통 의미하는 바를 나타내도록 바꾸면 이 식이 눈에 더 잘 들어올지도 모르겠습니다.
@@ -711,7 +711,7 @@ f(b) = sin (b)
중·고등학교에서 다항식을 배운 기억이 나시나요? 이렇게 생긴 합을 다항식이라고 합니다.
@@ -731,12 +731,12 @@ f(x) = a · x + b · x + c · x + d
"이항계수"의 형태를 띱니다. 이항계수라고 하면 어려워 보이지만 사실은 두 값을 섞는 것을 간단하게 나타낸 것입니다.
@@ -1124,11 +1124,11 @@ Bézier(n,t) = ❯ \underset binomial term\underbrace\binomni · \ \unders
(210,30), we use this Bézier curve:
Which gives us the curve we saw at the top of the article:
@@ -1256,9 +1256,9 @@ function Bezier(3,t,w[]):
Adding these ratio values to the regular Bézier curve function is fairly easy. Where the regular function is the following:
The function for rational Bézier curves has two more terms:
@@ -1478,8 +1478,8 @@ mixture = a · value + b · value
And that's easy:
@@ -1553,61 +1553,61 @@ m = a · value + (1 - a) · value
refer to coordinate values "in one or more dimensions":
Disregarding our actual coordinates for a moment, we have:
We can write this as a sum of four expressions:
And we can expand these expressions:
Furthermore, we can make all the 1 and 0 factors explicit:
And that , we can view as a series of four matrix operations:
@@ -2617,7 +2617,7 @@ Bézier(n,t) = ❯ w B (t) , where B (t) = \binomni · (1-t) · t
t
and 1-t
:
@@ -2626,9 +2626,9 @@ x = 1 x = ((1-t) + t) x = (1-t) x + t x = x (1-t) + x t
t
component:
@@ -2638,18 +2638,18 @@ Bézier(n,t)= (1-t) B(n,t) + t B(n,t)
I promise, it's about to make sense. We start with (1-t)
:
t part, but that's not a problem:
Let's do this:
where the matrix M is an n+1
by n
matrix, and looks like:
First, let's look at the derivative rule for Bézier curves, which is:
n) as:
n-1 and k-1 , we'll be on the right track.
And that's just a summation of lower order curves:
@@ -3070,7 +3070,7 @@ Bézier (t) ── = n · B (t) · (w - w ) + n · B
/>
We can rewrite this as a normal summation, and we're done:
@@ -3177,14 +3177,14 @@ tangent (t) = B' (t)
point, and then do whatever it is we want to do based on those directions:
@@ -3246,7 +3246,7 @@ y' = x · sin (\phi) + y · cos (\phi)
/>
Which is the "long" version of the following matrix transformation:
@@ -3737,10 +3737,10 @@ generateRMFrames(steps) -> frames:
derivatives section :
And then we turn this into our solution for t
using basic arithmetics:
@@ -3777,7 +3777,7 @@ B'(t) = a(1-t) + b(t)= 0,
you haven't, it looks like this:
@@ -3817,21 +3817,21 @@ B'(t) uses { v ,v ,v }, where v = 3(p -p ), v = 3(p -p ), v = 3(p -p )
/>
And then, using these v values, we can find out what our a , b , and c should be:
f
y (x) is zero, so that the next
t
is the same as the one we already have:
@@ -4449,11 +4449,11 @@ x = x - ───────
by -160, gives us:
@@ -4461,20 +4461,20 @@ x = x - ───────
become:
If we drop all the zero-terms, this gives us:
@@ -4581,7 +4581,7 @@ x = x - ───────
What we need to do is solve a simple equation:
@@ -4591,7 +4591,7 @@ C(t) = 0
circle being on the other side of the curve. So what does
C(t) look like? Actually something that seems not too hard:
@@ -4620,15 +4620,15 @@ C(t) = Bézier \prime(t) · Bézier \prime\prime(t) - Bézier \prime(t)
with the first and second derivatives, given our basis functions:
And of course the same functions for y :
t values, we end up with the following simple term function for
C(t) :
@@ -5167,16 +5167,16 @@ mapped = (x) = │ 1 2
First, let's look at the function for x(t):
We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:
@@ -5187,7 +5187,7 @@ x(t) = (-a + 3b- 3c + d)t + (3a - 6b + 3c)t + (-3a + 3b)t + a
known constants, we can trivially rewrite this (by moving the
x(t)
across the equal sign) as:
@@ -5278,7 +5278,7 @@ y = curve.get(t).y
@@ -5408,16 +5408,16 @@ length = | ⟍│(dx/dt) +(dy/dt) dt
shifting and scaling the inputs. Doing so, we get the following:
these tables would tell us that for
n=2 we must use the following values:
@@ -5634,14 +5634,14 @@ t = + ────
tiny bit:
@@ -5720,7 +5720,7 @@ function kappa(t, B):
circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:
@@ -6182,22 +6182,22 @@ C = u(t) · P + (1-u(t)) · P
(with thanks to Boris Zbarsky) shows us the following two formulae:
And
@@ -6208,7 +6208,7 @@ u(t) = ───────────
We start by observing that, given A
, B
, and C
, the following always holds:
And
@@ -6241,7 +6241,7 @@ ratio(t) = |───────────────|
ratio(t)
function to find A
:
@@ -6304,15 +6304,15 @@ A = B - ───────── = B + ─────────
B
point, and
B
and end point as a ratio, using
e2 coordinates must obey the standard de Casteljau rule for linear interpolation:
@@ -6396,7 +6396,7 @@ A = B - ───────── = B + ─────────
curve with a loop in it. To do this, we can use the
atan2 function:
@@ -6413,8 +6413,8 @@ A = B - ───────── = B + ─────────
d
:
Which seems simple enough. Unfortunately, when we expand that dist
function, things get a lot more problematic:
B, we can compute the associated
C
:
And then the associated A
:
@@ -7031,12 +7031,12 @@ A = B - ────────── = B + ──────────
form, where each line corresponds to a power of t, and each column is for a specific coefficient. First, we expand the function:
And then we (trivially) rearrange the terms across multiple lines:
With that arrangement, we can easily decompose this as a matrix multiplication:
So we write out the expansion and rearrange:
Which we can then decompose:
@@ -7212,10 +7212,10 @@ D = ┌ d d ... d ┐, where ╡ 1
i=n
fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:
T x M x C we talked about before, which gives us:
In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:
@@ -7308,7 +7308,7 @@ E(C) = (P - TMC) (P - TMC)
those, and then use that 𝕋 instead of
T in our error function:
@@ -7365,7 +7365,7 @@ E(C) = (P - 𝕋MC) (P - 𝕋MC)
taking the derivative, and determining where that derivative is zero:
@@ -7503,13 +7503,13 @@ C = M (𝕋 𝕋) 𝕋 P
previous and next point:
@@ -8298,7 +8298,7 @@ B'(1) = B'(0)
last control point through the last on-curve point. And mirroring any point A through any point B is really simple:
B(t). Easy enough:
N(t) always has length 1, which we can achieve by dividing
B'(t)
by its magnitude:
B'(t), with
t = 0
as start and
t = 1
as end:
φ:
First we solve for b :
which yields:
@@ -8828,7 +8828,7 @@ b = ────────
polynomial, and we know where the circle arc's actual point P is for angle φ/2:
2" (which is "half height" P
2 ), and so forth:
Wolfram Alpha is definitely the way to go. That said, let's get going:
k:
Which also gives us the commonly found value of 0.55228 for quarter circles, based on them having an angle of half π:
First, let's express the total error (given circular arc angle θ, and some k ) using standard calculus notation:
@@ -9961,7 +9961,7 @@ N (t) = ╡ i i+1
P(t), we can compute this point by evaluating
d(t) on a curve section between knots
i
and
i+1
:
@@ -10002,34 +10002,34 @@ d (t) = 0, d (t) = N (t) = ╡ i i+1
recursion diagram:
diff --git a/docs/news/2020-09-18.html b/docs/news/2020-09-18.html
index 7b6615c2..23faee7d 100644
--- a/docs/news/2020-09-18.html
+++ b/docs/news/2020-09-18.html
@@ -33,8 +33,8 @@
-
-
+
+
@@ -176,15 +176,15 @@
@@ -271,7 +271,7 @@ draw() {
you know where to go .
See you in the next post!
- — Pomax
+ — Pomax
diff --git a/docs/news/2020-11-22.html b/docs/news/2020-11-22.html
index 75da0c68..7023fa77 100644
--- a/docs/news/2020-11-22.html
+++ b/docs/news/2020-11-22.html
@@ -33,8 +33,8 @@
-
-
+
+
diff --git a/docs/news/index.html b/docs/news/index.html
index 0bb7c10c..e062a8a4 100644
--- a/docs/news/index.html
+++ b/docs/news/index.html
@@ -33,7 +33,7 @@
-
+
diff --git a/docs/news/rss.xml b/docs/news/rss.xml
index bfd59b4a..25651325 100644
--- a/docs/news/rss.xml
+++ b/docs/news/rss.xml
@@ -6,7 +6,7 @@
News updates for the primer on Bézier Curves by Pomax
en-GB
- Mon Jun 05 2023 00:41:07 +00:00
+ Mon Jul 24 2023 09:16:38 +00:00
https://pomax.github.io/bezierinfo/images/og-image.png
A Primer on Bézier Curves
@@ -17,19 +17,19 @@
Curve-circle intersections
https://pomax.github.io/bezierinfo/news/2020-11-22.html
-
+
<p>While the primer covered line/line, line/curve, and curve/curve intersections, there was one other obvious intersection conspicuously missing: circle/curve intersections. You'd think those were just an extension on the maths used for the other three, but unfortunately, this is not the case. Rather than using calculus, the only real way to determine where a polynomial curve intersects it is to sample the curve at a resolution high enough to find you intervals on the curve where there likely is an intersection, then refining that interval until you find actual intersections.</p>
<p>It is, in fact, rather similar to <a href="https://pomax.github.io/bezierinfo/#projections">projecting a point onto a bezier curve</a> where the point is the circle's center, and where the projection distance actually needs to match the circle radius, so: <a href="https://pomax.github.io/bezierinfo/#circleintersection">let's see how to do that</a>!</p>
<p>— <a href="https://mastodon.social/@TheRealPomax">Pomax</a></p>
- Sun Nov 22 2020 00:00:00 +00:00
+ Sat Nov 21 2020 16:00:00 +00:00
2020-11-22.html
-
Rewriting the tech stack
https://pomax.github.io/bezierinfo/news/2020-09-18.html
-
+
<p>Once upon a time, I needed to draw some Bezier curves because I was trying to create a Japanese kanji composition system that turned strokes into outlines, and that required knowing how to offset Bezier curves and... at the time (2011, time flies) there was no good single source of information for Bezier curves on the web. So I made one. Sure it started small, but it turns out that if you just keep adding bits to something, several years later you have quite the monster, and a single HTML file becomes intractible.</p>
<p>So, in 2016, when <a href="https://reactjs.org/">React.js</a> exploded onto the scene, I rewrote the primer as a React app, and it became a lot easier to maintain. Like, <em>a lot</em> a lot. However, there was a downside: no JS meant no content. Sure, server-side rendering sort of existed, but not really, and because the Primer is hosted through github, there was no "server" to run. Plus, trying to rehydrate an app the size of the Primer from a giant HTML file had truly <em>dire</em> performance.</p>
<p>So I left it a regular React app, and every time I thought "wouldn't it be nice if it was just... a web page again?" the browser landscape just hadn't caught up. Finally, in 2020, things are different: with a global pandemic, and some vacation time, and something random causing me to look up the state of HTML custom elements, everything was pointing at it being time to finally, <em>finally</em>, turn the Primer back into a normal web page.</p>
@@ -57,15 +57,15 @@
</ul>
<blockquote>
<!--
-
+
__ n=3 n-k k
-B(t) = ❯ \ P \binomnk(1-t) t
- cubic ‾‾ k=0
+B(t) = ❯ \ P \binomnk(1-t) t
+ cubic ‾‾ k=0
k
-
+
3 2 2 3
- = P (1-t) + 3 P (1-t) t + 3P (1-t)t + P t
-
+ = P (1-t) + 3 P (1-t) t + 3P (1-t)t + P t
+
0 1 2 3
-->
<img class="LaTeX SVG" src="./images/news/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.svg" width="401px" height="97px" loading="lazy">
@@ -105,7 +105,7 @@ draw() {
<tr><td>11</td></tr>
<tr><td>12</td></tr>
<tr><td>13</td></tr></table>
-
+
<ul>
<li>Responsive CSS, so the content intelligently reflows where possible.</li>
<li>A "Live build" setup for working on the content and code.</li>
@@ -118,7 +118,7 @@ draw() {
<p>— <a href="https://mastodon.social/@TheRealPomax">Pomax</a></p>
- Fri Sep 18 2020 00:00:00 +00:00
+ Thu Sep 17 2020 17:00:00 +00:00
2020-09-18.html
diff --git a/docs/ru-RU/index.html b/docs/ru-RU/index.html
index 6be66690..562515b7 100644
--- a/docs/ru-RU/index.html
+++ b/docs/ru-RU/index.html
@@ -34,7 +34,7 @@
-
+
@@ -174,7 +174,7 @@
3GY1HbQ2cH9V4xBLnRYdEfc42Nd1ZyjLZu
либо используя QR-код справа, если вы предпочитаете такой вид =)
-
+
@@ -590,7 +590,7 @@
80ти % до второй, вычислить результат можно следующим образом:
@@ -668,7 +668,7 @@ f(x) = cos (x)
внимаю следующий пример:
@@ -680,9 +680,9 @@ f(b) = sin (b)
Как здесь:
@@ -699,8 +699,8 @@ f(b) = sin (b)
наших функций:
@@ -736,7 +736,7 @@ f(b) = sin (b)
Возможно, вы помните полиномы из школьной программы. Они выглядят следующим образом:
@@ -756,12 +756,12 @@ f(x) = a · x + b · x + c · x + d
b и т.д. принимающими "биноминальную" форму. Звучит сложно, но на практике выглядит понятнее:
@@ -1159,11 +1159,11 @@ Bézier(n,t) = ❯ \underset биноминальный термин\underb
(25,190) и (210,250) заканчиваясь на (210,30), мы запишем это следующим образом:
Это производит кривую, график которой мы видели в первой главе этой статьи.
@@ -1296,9 +1296,9 @@ function Bezier(3,t,w[]):
Как и прочее, воплощение этого коэффициента не должно составить нам особого труда. Тогда как обычная функция:
Функция для соотносительных кривых Безье имеет два дополнительных термина:
@@ -1519,8 +1519,8 @@ mixture = a · value + b · value
суму более 100% на выводе, что можно записать как:
@@ -1598,61 +1598,61 @@ m = a · value + (1 - a) · value
P... для обозначения координат в "одном или более пространстве".
Обобщив, игнорируя конкретные значения, мы получим:
Это, в свою очередь, может быть записано как:
Последнее мы можем раскрыть, записав как:
Более того можно записать с коэффициентами 1 и 0, включив нивелированные термины:
И уже это можно рассматривать как серию четырех матричных операций:
@@ -2675,7 +2675,7 @@ Bézier(n,t) = ❯ w B (t) , where B (t) = \binomni · (1-t) · t
t
and 1-t
:
@@ -2684,9 +2684,9 @@ x = 1 x = ((1-t) + t) x = (1-t) x + t x = x (1-t) + x t
t
component:
@@ -2696,18 +2696,18 @@ Bézier(n,t)= (1-t) B(n,t) + t B(n,t)
I promise, it's about to make sense. We start with (1-t)
:
t part, but that's not a problem:
Let's do this:
where the matrix M is an n+1
by n
matrix, and looks like:
Для начала рассмотрим правило производных для кривых Безье:
n) как:
k-1 — мы на верном пути.
И это по сути формула функции сумы на 1 порядок ниже:
@@ -3130,7 +3130,7 @@ Bézier (t) ── = n · B (t) · (w - w ) + n · B
/>
Можно переписать по стандартной форме сумы, и готово:
@@ -3237,14 +3237,14 @@ tangent (t) = B' (t)
point, and then do whatever it is we want to do based on those directions:
@@ -3306,7 +3306,7 @@ y' = x · sin (\phi) + y · cos (\phi)
/>
Which is the "long" version of the following matrix transformation:
@@ -3798,10 +3798,10 @@ generateRMFrames(steps) -> frames:
derivatives section :
And then we turn this into our solution for t
using basic arithmetics:
@@ -3838,7 +3838,7 @@ B'(t) = a(1-t) + b(t)= 0,
you haven't, it looks like this:
@@ -3878,21 +3878,21 @@ B'(t) uses { v ,v ,v }, where v = 3(p -p ), v = 3(p -p ), v = 3(p -p )
/>
And then, using these v values, we can find out what our a , b , and c should be:
f
y (x) is zero, so that the next
t
is the same as the one we already have:
Мы переместим первую точку в начало координат, смещая все значания x на -120 и y на -160:
Затем, повернем кривую до оси X (новые значания x и y округлены в иллюстративных целях):
Итак, опуская все нулевые значения, получаем
@@ -4643,7 +4643,7 @@ x = x - ───────
What we need to do is solve a simple equation:
@@ -4653,7 +4653,7 @@ C(t) = 0
circle being on the other side of the curve. So what does
C(t) look like? Actually something that seems not too hard:
@@ -4682,15 +4682,15 @@ C(t) = Bézier \prime(t) · Bézier \prime\prime(t) - Bézier \prime(t)
with the first and second derivatives, given our basis functions:
And of course the same functions for y :
t values, we end up with the following simple term function for
C(t) :
@@ -5233,16 +5233,16 @@ mapped = (x) = │ 1 2
First, let's look at the function for x(t):
We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:
@@ -5253,7 +5253,7 @@ x(t) = (-a + 3b- 3c + d)t + (3a - 6b + 3c)t + (-3a + 3b)t + a
known constants, we can trivially rewrite this (by moving the
x(t)
across the equal sign) as:
@@ -5346,7 +5346,7 @@ y = curve.get(t).y
@@ -5476,16 +5476,16 @@ length = | ⟍│(dx/dt) +(dy/dt) dt
shifting and scaling the inputs. Doing so, we get the following:
these tables would tell us that for
n=2 we must use the following values:
@@ -5704,14 +5704,14 @@ t = + ────
tiny bit:
@@ -5790,7 +5790,7 @@ function kappa(t, B):
circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:
@@ -6255,22 +6255,22 @@ C = u(t) · P + (1-u(t)) · P
(with thanks to Boris Zbarsky) shows us the following two formulae:
And
@@ -6281,7 +6281,7 @@ u(t) = ───────────
We start by observing that, given A
, B
, and C
, the following always holds:
And
@@ -6314,7 +6314,7 @@ ratio(t) = |───────────────|
ratio(t)
function to find A
:
@@ -6379,15 +6379,15 @@ A = B - ───────── = B + ─────────
B
point, and
B
and end point as a ratio, using
e2 coordinates must obey the standard de Casteljau rule for linear interpolation:
@@ -6471,7 +6471,7 @@ A = B - ───────── = B + ─────────
curve with a loop in it. To do this, we can use the
atan2 function:
@@ -6488,8 +6488,8 @@ A = B - ───────── = B + ─────────
d
:
Which seems simple enough. Unfortunately, when we expand that dist
function, things get a lot more problematic:
B, we can compute the associated
C
:
And then the associated A
:
@@ -7112,12 +7112,12 @@ A = B - ────────── = B + ──────────
form, where each line corresponds to a power of t, and each column is for a specific coefficient. First, we expand the function:
And then we (trivially) rearrange the terms across multiple lines:
With that arrangement, we can easily decompose this as a matrix multiplication:
So we write out the expansion and rearrange:
Which we can then decompose:
@@ -7293,10 +7293,10 @@ D = ┌ d d ... d ┐, where ╡ 1
i=n
fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:
T x M x C we talked about before, which gives us:
In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:
@@ -7389,7 +7389,7 @@ E(C) = (P - TMC) (P - TMC)
those, and then use that 𝕋 instead of
T in our error function:
@@ -7446,7 +7446,7 @@ E(C) = (P - 𝕋MC) (P - 𝕋MC)
taking the derivative, and determining where that derivative is zero:
@@ -7585,13 +7585,13 @@ C = M (𝕋 𝕋) 𝕋 P
previous and next point:
@@ -8380,7 +8380,7 @@ B'(1) = B'(0)
last control point through the last on-curve point. And mirroring any point A through any point B is really simple:
B(t). Easy enough:
N(t) always has length 1, which we can achieve by dividing
B'(t)
by its magnitude:
B'(t), with
t = 0
as start and
t = 1
as end:
φ:
First we solve for b :
which yields:
@@ -8914,7 +8914,7 @@ b = ────────
polynomial, and we know where the circle arc's actual point P is for angle φ/2:
2" (which is "half height" P
2 ), and so forth:
Wolfram Alpha is definitely the way to go. That said, let's get going:
k:
Which also gives us the commonly found value of 0.55228 for quarter circles, based on them having an angle of half π:
First, let's express the total error (given circular arc angle θ, and some k ) using standard calculus notation:
@@ -10047,7 +10047,7 @@ N (t) = ╡ i i+1
P(t), we can compute this point by evaluating
d(t) on a curve section between knots
i
and
i+1
:
@@ -10088,34 +10088,34 @@ d (t) = 0, d (t) = N (t) = ╡ i i+1
recursion diagram:
diff --git a/docs/uk-UA/index.html b/docs/uk-UA/index.html
index ba204a57..96c3fbe5 100644
--- a/docs/uk-UA/index.html
+++ b/docs/uk-UA/index.html
@@ -39,7 +39,7 @@
-
+
@@ -173,7 +173,7 @@
3GY1HbQ2cH9V4xBLnRYdEfc42Nd1ZyjLZu
or use the QR code on the right, if that's the kind of convenience you prefer =)
-
+
@@ -573,7 +573,7 @@
thus 80% the distance away from the second point) then we can compute that really easily:
@@ -647,7 +647,7 @@ f(x) = cos (x)
So far, so good. Now, let's look at parametric functions, and how they cheat. Let's take the following two functions:
@@ -658,9 +658,9 @@ f(b) = sin (b)
function. Parametric functions cheat by changing that. In a parametric function all the different functions share a variable, like this:
@@ -678,8 +678,8 @@ f(b) = sin (b)
obvious:
@@ -714,7 +714,7 @@ f(b) = sin (b)
You may remember polynomials from high school. They're those sums that look like this:
@@ -735,12 +735,12 @@ f(x) = a · x + b · x + c · x + d
values:
@@ -1132,11 +1132,11 @@ Bézier(n,t) = ❯ \underset binomial term\underbrace\binomni · \ \unders
(210,30), we use this Bézier curve:
Which gives us the curve we saw at the top of the article:
@@ -1266,9 +1266,9 @@ function Bezier(3,t,w[]):
Adding these ratio values to the regular Bézier curve function is fairly easy. Where the regular function is the following:
The function for rational Bézier curves has two more terms:
@@ -1490,8 +1490,8 @@ mixture = a · value + b · value
And that's easy:
@@ -1567,61 +1567,61 @@ m = a · value + (1 - a) · value
refer to coordinate values "in one or more dimensions":
Disregarding our actual coordinates for a moment, we have:
We can write this as a sum of four expressions:
And we can expand these expressions:
Furthermore, we can make all the 1 and 0 factors explicit:
And that , we can view as a series of four matrix operations:
@@ -2637,7 +2637,7 @@ Bézier(n,t) = ❯ w B (t) , where B (t) = \binomni · (1-t) · t
t
and 1-t
:
@@ -2646,9 +2646,9 @@ x = 1 x = ((1-t) + t) x = (1-t) x + t x = x (1-t) + x t
t
component:
@@ -2658,18 +2658,18 @@ Bézier(n,t)= (1-t) B(n,t) + t B(n,t)
I promise, it's about to make sense. We start with (1-t)
:
t part, but that's not a problem:
Let's do this:
where the matrix M is an n+1
by n
matrix, and looks like:
First, let's look at the derivative rule for Bézier curves, which is:
n) as:
n-1 and k-1 , we'll be on the right track.
And that's just a summation of lower order curves:
@@ -3090,7 +3090,7 @@ Bézier (t) ── = n · B (t) · (w - w ) + n · B
/>
We can rewrite this as a normal summation, and we're done:
@@ -3197,14 +3197,14 @@ tangent (t) = B' (t)
point, and then do whatever it is we want to do based on those directions:
@@ -3266,7 +3266,7 @@ y' = x · sin (\phi) + y · cos (\phi)
/>
Which is the "long" version of the following matrix transformation:
@@ -3757,10 +3757,10 @@ generateRMFrames(steps) -> frames:
derivatives section :
And then we turn this into our solution for t
using basic arithmetics:
@@ -3797,7 +3797,7 @@ B'(t) = a(1-t) + b(t)= 0,
you haven't, it looks like this:
@@ -3837,21 +3837,21 @@ B'(t) uses { v ,v ,v }, where v = 3(p -p ), v = 3(p -p ), v = 3(p -p )
/>
And then, using these v values, we can find out what our a , b , and c should be:
f
y (x) is zero, so that the next
t
is the same as the one we already have:
@@ -4471,11 +4471,11 @@ x = x - ───────
by -160, gives us:
@@ -4483,20 +4483,20 @@ x = x - ───────
become:
If we drop all the zero-terms, this gives us:
@@ -4607,7 +4607,7 @@ x = x - ───────
What we need to do is solve a simple equation:
@@ -4617,7 +4617,7 @@ C(t) = 0
circle being on the other side of the curve. So what does
C(t) look like? Actually something that seems not too hard:
@@ -4646,15 +4646,15 @@ C(t) = Bézier \prime(t) · Bézier \prime\prime(t) - Bézier \prime(t)
with the first and second derivatives, given our basis functions:
And of course the same functions for y :
t values, we end up with the following simple term function for
C(t) :
@@ -5197,16 +5197,16 @@ mapped = (x) = │ 1 2
First, let's look at the function for x(t):
We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:
@@ -5217,7 +5217,7 @@ x(t) = (-a + 3b- 3c + d)t + (3a - 6b + 3c)t + (-3a + 3b)t + a
known constants, we can trivially rewrite this (by moving the
x(t)
across the equal sign) as:
@@ -5310,7 +5310,7 @@ y = curve.get(t).y
@@ -5440,16 +5440,16 @@ length = | ⟍│(dx/dt) +(dy/dt) dt
shifting and scaling the inputs. Doing so, we get the following:
these tables would tell us that for
n=2 we must use the following values:
@@ -5668,14 +5668,14 @@ t = + ────
tiny bit:
@@ -5754,7 +5754,7 @@ function kappa(t, B):
circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:
@@ -6218,22 +6218,22 @@ C = u(t) · P + (1-u(t)) · P
(with thanks to Boris Zbarsky) shows us the following two formulae:
And
@@ -6244,7 +6244,7 @@ u(t) = ───────────
We start by observing that, given A
, B
, and C
, the following always holds:
And
@@ -6277,7 +6277,7 @@ ratio(t) = |───────────────|
ratio(t)
function to find A
:
@@ -6342,15 +6342,15 @@ A = B - ───────── = B + ─────────
B
point, and
B
and end point as a ratio, using
e2 coordinates must obey the standard de Casteljau rule for linear interpolation:
@@ -6434,7 +6434,7 @@ A = B - ───────── = B + ─────────
curve with a loop in it. To do this, we can use the
atan2 function:
@@ -6451,8 +6451,8 @@ A = B - ───────── = B + ─────────
d
:
Which seems simple enough. Unfortunately, when we expand that dist
function, things get a lot more problematic:
B, we can compute the associated
C
:
And then the associated A
:
@@ -7074,12 +7074,12 @@ A = B - ────────── = B + ──────────
form, where each line corresponds to a power of t, and each column is for a specific coefficient. First, we expand the function:
And then we (trivially) rearrange the terms across multiple lines:
With that arrangement, we can easily decompose this as a matrix multiplication:
So we write out the expansion and rearrange:
Which we can then decompose:
@@ -7255,10 +7255,10 @@ D = ┌ d d ... d ┐, where ╡ 1
i=n
fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:
T x M x C we talked about before, which gives us:
In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:
@@ -7351,7 +7351,7 @@ E(C) = (P - TMC) (P - TMC)
those, and then use that 𝕋 instead of
T in our error function:
@@ -7408,7 +7408,7 @@ E(C) = (P - 𝕋MC) (P - 𝕋MC)
taking the derivative, and determining where that derivative is zero:
@@ -7546,13 +7546,13 @@ C = M (𝕋 𝕋) 𝕋 P
previous and next point:
@@ -8341,7 +8341,7 @@ B'(1) = B'(0)
last control point through the last on-curve point. And mirroring any point A through any point B is really simple:
B(t). Easy enough:
N(t) always has length 1, which we can achieve by dividing
B'(t)
by its magnitude:
B'(t), with
t = 0
as start and
t = 1
as end:
φ:
First we solve for b :
which yields:
@@ -8873,7 +8873,7 @@ b = ────────
polynomial, and we know where the circle arc's actual point P is for angle φ/2:
2" (which is "half height" P
2 ), and so forth:
Wolfram Alpha is definitely the way to go. That said, let's get going:
k:
Which also gives us the commonly found value of 0.55228 for quarter circles, based on them having an angle of half π:
First, let's express the total error (given circular arc angle θ, and some k ) using standard calculus notation:
@@ -10006,7 +10006,7 @@ N (t) = ╡ i i+1
P(t), we can compute this point by evaluating
d(t) on a curve section between knots
i
and
i+1
:
@@ -10047,34 +10047,34 @@ d (t) = 0, d (t) = N (t) = ╡ i i+1
recursion diagram:
diff --git a/docs/zh-CN/index.html b/docs/zh-CN/index.html
index c2d459e1..8af2b9d6 100644
--- a/docs/zh-CN/index.html
+++ b/docs/zh-CN/index.html
@@ -35,7 +35,7 @@
-
+
@@ -172,7 +172,7 @@
3GY1HbQ2cH9V4xBLnRYdEfc42Nd1ZyjLZu
或者使用右边的二维码,如果你倾向于这种便利的方式 =)
-
+
将上式改写为与原式相似的形式有助于看出它们的区别。先写出原式,再写出导数:
-
-
+
+
+
+
有什么区别?对于实际的贝塞尔曲线而言几乎没有区别!虽然次数降低了(从n 次变为n -1次),但是贝塞尔函数没有改变。唯一的真正的区别在于推导表示曲线的函数时权重如何变化。如果有A、B、C、D四个点,那么导数有三个点,二阶导数有两个点,三阶导数有一个点:
-
+
+
只要有多于一个权重即可运用这一方法。只剩一个权重时,下一步会出现k =0,而贝塞尔函数的和式因为无项可加而化为零。因此二次函数没有二阶导数,三次函数没有三阶导数,更一般地有n 次函数有n -1阶(有意义的)导数,其更高阶导数为零。
@@ -2633,30 +2904,30 @@ Bézier'(n,t) = ❯ Bézier(n-1,t) · n · (w -w )
如果要将物体沿曲线移动或者从曲线附近“移向远处”,那么与之最相关的两个向量为曲线的切向量和法向量,而这两者都非常容易求得。切向量用于沿曲线移动或者对准曲线方向,它标志着曲线在指定点的行进方向,而且就是曲线函数的一阶导数:
此即所需的方向向量。可以在每一点将方向向量规范化后得到单位方向向量(即长度为1.0),再根据这些方向进行所需的操作:
切向量对于沿曲线移动很有用,但如果要从曲线附近“移向远处”,而且移动方向与曲线在某点t 处垂直,那该怎么办?这时需要的是法 向量。这一向量与曲线的方向保持垂直,且长度通常为1.0,因此只需旋转单位方向向量即可:
-
+
+
其实旋转坐标只要知道方法就非常简单——“施加旋转矩阵
为了将点(x ,y )(绕(0,0))旋转φ 度得到点(x' ,y' ),可以使用以下简洁的计算式:
对应“短”版本的矩阵变换为:
@@ -2839,51 +3125,19 @@ y' = x · sin (\phi) + y · cos (\phi)
实现旋转最小化标架
首先假设已有函数用于计算上文提及的指定点的弗勒内标架,输出的标架具有如下性质:
-
-
-
- 1
-
-
-
-
-
- 2
-
-
- 3
-
-
- 4
-
-
- 5
-
-
- 6
-
-
-
+}
再如下写出生成一系列旋转最小化标架的函数:
-
-
-
- 1
-
-
-
-
-
- 2
-
-
- 3
-
-
- 4
-
-
- 5
-
-
- 6
-
-
- 7
-
-
- 8
-
-
- 9
-
-
- 10
-
-
- 11
-
-
- 12
-
-
- 13
-
-
- 14
-
-
- 15
-
-
- 16
-
-
- 17
-
-
- 18
-
-
- 19
-
-
- 20
-
-
- 21
-
-
- 22
-
-
- 23
-
-
- 24
-
-
- 25
-
-
- 26
-
-
- 27
-
-
- 28
-
-
-
+ frames.add(x1)
即使忽略注释,代码也明显比计算单个弗勒内标架的多,但也没有多得离谱,而且得到了长得更好的法向量。
@@ -3083,10 +3251,10 @@ generateRMFrames(steps) -> frames:
derivatives section :
And then we turn this into our solution for t
using basic arithmetics:
@@ -3123,7 +3291,7 @@ B'(t) = a(1-t) + b(t)= 0,
you haven't, it looks like this:
@@ -3163,21 +3331,21 @@ B'(t) uses { v ,v ,v }, where v = 3(p -p ), v = 3(p -p ), v = 3(p -p )
/>
And then, using these v values, we can find out what our a , b , and c should be:
f
y (x) is zero, so that the next
t
is the same as the one we already have:
@@ -3797,11 +3965,11 @@ x = x - ───────
by -160, gives us:
@@ -3809,20 +3977,20 @@ x = x - ───────
become:
If we drop all the zero-terms, this gives us:
@@ -3933,7 +4101,7 @@ x = x - ───────
What we need to do is solve a simple equation:
@@ -3943,7 +4111,7 @@ C(t) = 0
circle being on the other side of the curve. So what does
C(t) look like? Actually something that seems not too hard:
@@ -3972,15 +4140,15 @@ C(t) = Bézier \prime(t) · Bézier \prime\prime(t) - Bézier \prime(t)
with the first and second derivatives, given our basis functions:
And of course the same functions for y :
t values, we end up with the following simple term function for
C(t) :
@@ -4521,16 +4689,16 @@ mapped = (x) = │ 1 2
First, let's look at the function for x(t):
We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:
@@ -4541,7 +4709,7 @@ x(t) = (-a + 3b- 3c + d)t + (3a - 6b + 3c)t + (-3a + 3b)t + a
known constants, we can trivially rewrite this (by moving the
x(t)
across the equal sign) as:
@@ -4634,7 +4802,7 @@ y = curve.get(t).y
@@ -4764,16 +4932,16 @@ length = | ⟍│(dx/dt) +(dy/dt) dt
shifting and scaling the inputs. Doing so, we get the following:
these tables would tell us that for
n=2 we must use the following values:
@@ -4992,14 +5160,14 @@ t = + ────
tiny bit:
@@ -5078,7 +5246,7 @@ function kappa(t, B):
circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:
@@ -5540,22 +5708,22 @@ C = u(t) · P + (1-u(t)) · P
(with thanks to Boris Zbarsky) shows us the following two formulae:
And
@@ -5566,7 +5734,7 @@ u(t) = ───────────
We start by observing that, given A
, B
, and C
, the following always holds:
And
@@ -5599,7 +5767,7 @@ ratio(t) = |───────────────|
ratio(t)
function to find A
:
@@ -5662,15 +5830,15 @@ A = B - ───────── = B + ─────────
B
point, and
B
and end point as a ratio, using
e2 coordinates must obey the standard de Casteljau rule for linear interpolation:
@@ -5754,7 +5922,7 @@ A = B - ───────── = B + ─────────
curve with a loop in it. To do this, we can use the
atan2 function:
@@ -5771,8 +5939,8 @@ A = B - ───────── = B + ─────────
d
:
Which seems simple enough. Unfortunately, when we expand that dist
function, things get a lot more problematic:
B, we can compute the associated
C
:
And then the associated A
:
@@ -6393,12 +6561,12 @@ A = B - ────────── = B + ──────────
form, where each line corresponds to a power of t, and each column is for a specific coefficient. First, we expand the function:
And then we (trivially) rearrange the terms across multiple lines:
With that arrangement, we can easily decompose this as a matrix multiplication:
So we write out the expansion and rearrange:
Which we can then decompose:
@@ -6574,10 +6742,10 @@ D = ┌ d d ... d ┐, where ╡ 1
i=n
fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:
T x M x C we talked about before, which gives us:
In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:
@@ -6670,7 +6838,7 @@ E(C) = (P - TMC) (P - TMC)
those, and then use that 𝕋 instead of
T in our error function:
@@ -6727,7 +6895,7 @@ E(C) = (P - 𝕋MC) (P - 𝕋MC)
taking the derivative, and determining where that derivative is zero:
@@ -6865,13 +7033,13 @@ C = M (𝕋 𝕋) 𝕋 P
previous and next point:
@@ -7660,7 +7828,7 @@ B'(1) = B'(0)
last control point through the last on-curve point. And mirroring any point A through any point B is really simple:
B(t). Easy enough:
N(t) always has length 1, which we can achieve by dividing
B'(t)
by its magnitude:
B'(t), with
t = 0
as start and
t = 1
as end:
φ:
First we solve for b :
which yields:
@@ -8192,7 +8360,7 @@ b = ────────
polynomial, and we know where the circle arc's actual point P is for angle φ/2:
2" (which is "half height" P
2 ), and so forth:
Wolfram Alpha is definitely the way to go. That said, let's get going:
k:
Which also gives us the commonly found value of 0.55228 for quarter circles, based on them having an angle of half π:
First, let's express the total error (given circular arc angle θ, and some k ) using standard calculus notation:
@@ -9318,7 +9486,7 @@ N (t) = ╡ i i+1
P(t), we can compute this point by evaluating
d(t) on a curve section between knots
i
and
i+1
:
@@ -9359,34 +9527,34 @@ d (t) = 0, d (t) = N (t) = ╡ i i+1
recursion diagram: