forked from Pomax/bezierinfo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
executable file
·489 lines (406 loc) · 21.4 KB
/
index.html
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
<!doctype html>
<html>
<head>
<!-- referral tracking -->
<script src="js/referrer.js"></script>
<!-- DOM manipulation, the kinder way -->
<script src="js/tiny-toolkit-min.js"></script>
<!-- page information -->
<meta charset="utf-8">
<title>A Primer on Bézier Curves</title>
<!-- styling -->
<link rel="stylesheet" media="screen" href="style.css">
<link rel="stylesheet" media="print" href="print.css">
<!-- JS API improvements -->
<script>
// give NodeList a .forEach() and .toArray(), because: seriously.
(function(p,n,a,f,t){n=n[p];a=a[p];n[f]=a[f];n[t]=function(){var
r=[];this[f](function(n){r.push(n);});return r;}}
("prototype",NodeList,Array,"forEach","toArray"));
</script>
<!-- MathJax for beautiful LaTeX functions -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
displayAlign: "left",
displayIndent: "2em",
TeX: {
extensions: ["color.js"]
},
skipStartupTypeset: true
});
</script>
<script src="js/preprint.js"></script>
<script src="js/howtocode.js"></script>
<script src="js/sketchloader.js"></script>
<script src="js/colorpreprocess.js"></script>
<script src="js/processing.patched.js"></script>
<!-- opengraph information -->
<meta property="og:title" content="A Primer on Bézier Curves">
<meta property="og:type" content="text">
<meta property="og:url" content="http://pomax.github.io/bezierinfo">
<meta property="og:description" content="A detailed explanation of Bézier curves, and how to do the many things that we commonly want to do with them.">
<meta property="og:locale" content="en_GB">
<meta property="og:type" content="article">
<meta property="og:published_time" content="2013-06-13 12:00:00">
<meta property="og:author" content="Mike 'Pomax' Kamermans">
<meta property="og:section" content="Bézier Curves">
<meta property="og:tag" content="Bézier Curve">
<!-- <link rel="component" href="webcomponents/github-components.html"> -->
<link rel="stylesheet" type="text/css" href="EasyPageComments.css"/>
<script>
var debug = (function() {
if ("console" in window) {
return function(msg) {
window.console.log(msg);
};
}
return function(){};
}());
</script>
<script>
function setupClippingButton(sketch) {
var b = document.getElementById("clippingButton");
if(b) {
b.onclick = function() {
debug("clipping...");
sketch.kickOff();
};
}
}
// helper for the above script.
function handleMouseMoved(sketch, p, mx, my) {
if (sketch.handleMouseMoved) {
sketch.handleMouseMoved(p, mx, my);
}
}
</script>
<script src="js/nunjucks.js"></script>
<script src="js/sectionloading.js"></script>
</head>
<body>
<img id="ribbonimg" src="images/ribbon.png" alt="This page on GitHub" border=0 usemap="#githubmap">
<map name="githubmap">
<area shape="poly" coords="30,0, 200,0, 200,114" href="http://github.com/pomax/bezierinfo" alt="This page on GitHub">
</map>
<!-- actual article -->
<article>
<!-- AddThis social buttons. Fairly unobtrusive -->
<div id="sidebar" style="position:relative; left:-52px">
<style>
.addthis_floating_style { position: relative!important; height:0px; top:8.25em; background:inherit!important; }
.addthis_toolbox a { opacity: 0.3; }
.addthis_toolbox a:hover { opacity: 1; }
</style>
<!-- AddThis Button BEGIN -->
<div class="addthis_toolbox addthis_floating_style addthis_16x16_style">
<a addthis:title="Reading @TheRealPomax's Primer on Bézier Curves:" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_twitter"></a>
<a addthis:title="A Primer on Bézier Curves" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_facebook"></a>
<a addthis:title="@TheRealPomax's Primer on Bézier Curves" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_google_plusone_share"></a>
<a addthis:title="A Primer on Bézier Curves" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_linkedin"></a>
<a addthis:title="A Primer on Bézier Curves" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_reddit"></a>
<a addthis:title="How much do you want to know about Bézier Curves?" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_hackernews"></a>
<a addthis:title="How much do you want to know about Bézier Curves?" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_digg"></a>
<a addthis:title="A Primer on Bézier Curves" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_stumbleupon"></a>
<a addthis:title="A Primer on Bézier Curves" addthis:url="http://pomax.github.io/bezierinfo" class="addthis_button_compact"></a>
</div>
<!-- AddThis Button END -->
</div>
<header>
<h1>A Primer on Bézier Curves</h1>
</header>
<section id="preface">
<div id="navbar">
<h3>Table of Contents</h3>
<ol>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#explanation">How do Bézier curves work?</a></li>
<li><a href="#control">Controlling Bézier curvatures</a></li>
<li><a href="#matrix">Bézier curvatures as matrix operations</a></li>
<li><a href="#decasteljau">de Casteljau's algorithm</a></li>
<li><a href="#splitting">Splitting curves</a></li>
<li><a href="#matrixsplit">Splitting curves using matrices</a></li>
<li><a href="#reordering">Lowering and elevating curve order</a></li>
<li><a href="#derivatives">Derivatives</a></li>
<li><a href="#pointvectors">Tangents and normals</a></li>
<li><a href="#components">Component functions</a></li>
<li><a href="#extremities">Finding extremities</a></li>
<li><a href="#boundingbox">Bounding boxes</a></li>
<li><a href="#aligning">Aligning curves</a></li>
<li><a href="#tightbounds">Tight boxes</a></li>
<li><a href="#canonical">The canonical form (for cubic curves)</a></li>
<li><a href="#arclength">Arc length</a></li>
<li><a href="#tracing">Tracing a curve at fixed distance intervals</a></li>
<li><a href="#intersections">Intersections</a></li>
<li><a href="#curveintersection">Curve/curve intersection</a></li>
<li><a href="#moulding">Curve moulding (using the projection ratio)</a></li>
<li><a href="#pointcurves">Creating a curve from three points</a></li>
<li><a href="#catmullconv">Bézier curves and Catmull-Rom curves</a></li>
<li><a href="#catmullmoulding">Creating a Catmull-Rom curve from three points</a></li>
<li><a href="#polybezier">Forming poly-Bézier curves</a></li>
<li><a href="#shapes">Boolean shape operations</a></li>
<li><a href="#projections">Projecting a point onto a Bézier curve</a></li>
<li><a href="#offsetting">Curve offsetting</a></li>
<li><a href="#graduatedoffset">Graduated curve offsetting</a></li>
<li><a href="#circles">Circles and quadratic Bézier curves</a></li>
<li><a href="#circles_cubic">Circles and cubic Bézier curves</a></li>
<li><a href="#arcapproximation">Approximating Bézier curves with circles</a></li>
<li><a href="#arcarea">Signed area of a Bézier curve</a></li>
<li><a href="#issues">Todo list</a></li>
<li><a href="#comments">Comments and questions</a></li></ol>
</div>
<p>In order to draw things in 2D, we usually rely on lines, which typically get classified
into two categories: straight lines, and curves. The first of these are as easy to draw as they
are easy to make a computer draw. Give a computer the first and last point in the line, and
BAM! straight line. No questions asked.</p>
<p>Curves, however, are a much bigger problem. While we can draw curves with ridiculous ease
freehand, computers are a bit handicapped in that they can't draw curves unless there is a
mathematical function that describes how it should be drawn. In fact, they even need this for
straight lines, but the function is ridiculously easy, so we tend to ignore that as far as
computers are concerned, all lines are "functions", regardless of whether they're straight
or curves. However, that does mean that we need to come up with fast-to-compute functions that
lead to nice looking curves on a computer. There's a number of these, and in this article
we'll focus on a particular function that has received quite a bit of attention, and is used
in pretty much anything that can draw curves: "Bézier" curves</p>
<p>They're named after <a href="https://en.wikipedia.org/wiki/Pierre_B%C3%A9zier">Pierre
Bézier</a>, who is principally responsible for getting them known to the world as a curve
well-suited for design work (working for Renault and publishing his investigations in 1962),
although he was not the first, or only one, to "invent" these type of curves.
One might be tempted to say that the mathematician <a href="https://en.wikipedia.org/wiki/Paul_de_Casteljau">Paul
de Casteljau</a> was first, investigating the nature of these curves in 1959 while working at
Citroën, coming up with a really elegant way of figuring out how to draw them. However, de
Casteljau did not publish his work, making the question "who was first" hard to answer in
any absolute sense. Or is it? Bézier curves are, at their core, "Bernstein polynomials", a family
of mathematical functions investigated by
<a href="https://en.wikipedia.org/wiki/Sergei_Natanovich_Bernstein">Sergei Natanovich Bernstein</a>,
with publications on them at least as far back as 1912. Anyway, that's mostly trivia, what
you are more likely to care about is that these curves are handy: you can link up multiple
Bézier curves so that the combination looks like a single curve. If you've ever drawn Photoshop
"paths" or worked with vector drawing programs like Flash, Illustrator or Inkscape, those curves
you've been drawing are Bézier curves.</p>
<p>So, what if you need to program them yourself? What are the pitfalls? How do you draw them?
What are the bounding boxes, how do you determine intersections, how can you extrude a curve,
in short: how do you do everything that you might want when you do with these curves? That's
what this page is for. Prepare to be mathed.</p>
<div id="article-notes">
<h2 style="font-style:italic;">All Bézier graphics are interactive.</h2>
<p>This page uses <a href="http://processing.org">Processing</a> examples, rendering as
interactive graphics on the page using <a href="http://processingjs.org">Processing.js</a>,
which means you don't need any plugins if you're on a modern browser. (If you
are still using IE8 because you're on Windows XP, be aware Microsoft would rather you start
using something like Firefox than keep using IE8, because IE8 does not support the internet
anymore. It was already a little behind when it was first released, but today it literally
doesn't support the internet, a bit like the difference between wordpad and Word. IE8 is
no longer a web browser, it's a legacy application). It also uses math, in LaTeX form, which
is typeset using the most excellent <a href="http://mathjax.org">MathJax</a> library.</p>
<h2 style="font-style:italic;">Examples have a "view source" option.</h2>
<p>Just seeing that the guy who wrote the article knows how to write the code needed to
demonstrate Bézier curve things is basically useless, I think you'll agree. You don't benefit
from me going: <em>"Look at me, I know how to program, ooooh~"</em>. So to make things <em>useful</em>,
all graphics on this page have "view source" links. Click them, copy the source code, fire
up the <a href="http://processing.org/download/">Processing PDE</a>, paste the code, and
hit "play". You should see the exact same thing now running on your own computer as you're
seeing in the browser. This is working code, and you can trace everything I do. Regardless
of whether you <em>want</em> to, I consider it important that you can. And the kicker is
this code is in the public domain. I waive all rights to it. Do with it what you want, to
me this is trivial code and it would be ridiculous to claim it as anything other than "I
just wrote this to demonstrate how things work".</p>
<h2 style="font-style:italic;">Questions, comments:</h2>
If you have suggestions for new sections, hit up the <a href="https://github.com/pomax/bezierinfo/issues">github
issue tracker</a> (also reachable from the repo linked to in the upper right). If you have
questions about the material, there's currently no comment section while I'm doing the rewrite,
but you can use the issue tracker for that as well. Once the rewrite is done, I'll add a general
comment section back in, and maybe a more topical "select this section of text and hit the
'question' button to ask a question about it" system. We'll see.
<p>—Pomax (or in the tweetworld, <a href="https://twitter.com/TheRealPomax">@TheRealPomax</a>)</p>
</div>
</section>
<section id="introduction">
<h2 data-num="1">Introduction</h2>
<script> inject("introduction"); </script>
</section>
<section id="explanation">
<h2>How do Bézier curves work?</h2>
<script> inject("explanation"); </script>
</section>
<section id="control">
<h2>Controlling Bézier curvatures</h2>
<script> inject("control"); </script>
</section>
<section id="matrix">
<h2>Bézier curvatures as matrix operations</h2>
<script> inject("matrix"); </script>
</section>
<section id="decasteljau">
<h2>de Casteljau's algorithm</h2>
<script> inject("decasteljau"); </script>
</section>
<section id="splitting">
<h2>Splitting curves</h2>
<script> inject("splitting"); </script>
</section>
<section id="matrixsplit">
<h2>Splitting curves using matrices</h2>
<script> inject("matrixsplit"); </script>
</section>
<section id="reordering">
<h2>Lowering and elevating curve order</h2>
<script> inject("reordering"); </script>
</section>
<section id="derivatives">
<h2>Derivatives</h2>
<script> inject("derivatives"); </script>
</section>
<section id="pointvectors">
<h2>Tangents and normals</h2>
<script> inject("pointvectors"); </script>
</section>
<section id="components">
<h2>Component functions</h2>
<script> inject("components"); </script>
</section>
<section id="extremities">
<h2>Finding extremities</h2>
<script> inject("extremities"); </script>
</section>
<section id="boundingbox">
<h2>Bounding boxes</h2>
<script> inject("boundingbox"); </script>
</section>
<section id="aligning">
<h2>Aligning curves</h2>
<script> inject("aligning"); </script>
</section>
<section id="tightbounds">
<h2>Tight boxes</h2>
<script> inject("tightbounds"); </script>
</section>
<section id="canonical">
<h2>The canonical form (for cubic curves)</h2>
<script> inject("canonical"); </script>
</section>
<section id="arclength">
<h2>Arc length</h2>
<script> inject("arclength"); </script>
</section>
<section id="tracing">
<h2>Tracing a curve at fixed distance intervals</h2>
<script> inject("tracing"); </script>
</section>
<section id="intersections">
<h2>Intersections</h2>
<script> inject("intersections"); </script>
</section>
<section id="curveintersection">
<h2>Curve/curve intersection</h2>
<script> inject("curveintersection"); </script>
</section>
<section id="moulding">
<h2>Curve moulding (using the projection ratio)</h2>
<script> inject("moulding"); </script>
</section>
<section id="pointcurves">
<h2>Creating a curve from three points</h2>
<script> inject("pointcurves"); </script>
</section>
<section id="catmullconv">
<h2>Bézier curves and Catmull-Rom curves</h2>
<script> inject("catmullconv"); </script>
</section>
<section id="catmullmoulding">
<h2>Creating a Catmull-Rom curve from three points</h2>
<script> inject("catmullmoulding"); </script>
</section>
<section id="polybezier">
<h2>Forming poly-Bézier curves</h2>
<script> inject("polybezier"); </script>
</section>
<section id="shapes">
<h2>Boolean shape operations</h2>
<script> inject("shapes"); </script>
</section>
<section id="projections">
<h2>Projecting a point onto a Bézier curve</h2>
<script> inject("projections"); </script>
</section>
<section id="offsetting">
<h2>Curve offsetting</h2>
<script> inject("offsetting"); </script>
</section>
<section id="graduatedoffset">
<h2>Graduated curve offsetting</h2>
<script> inject("graduatedoffset"); </script>
</section>
<section id="circles">
<h2>Circles and quadratic Bézier curves</h2>
<script> inject("circles"); </script>
</section>
<section id="circles_cubic">
<h2>Circles and cubic Bézier curves</h2>
<script> inject("circles_cubic"); </script>
</section>
<section id="arcapproximation">
<h2>Approximating Bézier curves with circles</h2>
<script> inject("arcapproximation"); </script>
</section>
<section id="arcarea">
<h2>Signed area of a Bézier curve</h2>
<script> inject("arcarea"); </script>
</section>
<hr> <!-- ============================================================================== -->
<section id="issues">
<h2>Todo list</h2>
<ol>
<li>Programming tricks for fast curves</li>
<li>A reference and further reading section</li>
</ol>
<p>If there's anything missing from this list, please file an issue on github (link's in the
upper right corner), and I'll add it to this list (while I write up some code to cleanly
pull in gh-issues as a 'comment feed'... probably using web components).</p>
</section>
<hr> <!-- ============================================================================== -->
<section id="comments">
<h2>Comments and questions</h2>
<div id="commentlist"></div>
<p>Have a question or comment? Simply fill in the following form, and hit post.
No login required, because I'm sure we're all tired of having to log in just to
speak our mind at this point. And the security question should be pretty obvious.</p>
<div id="commentform"></div>
</section>
<footer id="copyright">
This article is © 2011-2014 to me, Mike "Pomax" Kamermans, but all the code used and
linked is in the public domain. Go do something cool with it.
</footer>
</article>
<div id="scriptblock">
<!-- scripts can come last so they don't hold up the DOM -->
<script src="js/autonav.js"></script>
<script type="text/javascript">
if(window.location.toString().indexOf("localhost") === -1) {
// no tracking info: http://support.addthis.com/customer/portal/articles/1013558-removing-all-hashtags-anchors-from-your-urls
var addthis_config = addthis_config||{};
addthis_config.data_track_clickback = false;
addthis_config.data_track_addressbar = false;
var script = document.createElement("script");
script.setAttribute("async", true);
script.src = "http://s7.addthis.com/js/300/addthis_widget.js#pubid=xa-516a3187281448fc";
document.head.appendChild(script);
function showEasyPageComments(name, data) {
if(name==="bezierinfo") {
document.getElementById('commentlist').innerHTML = data; }}
function showEasyPageCommentForm(name, data) {
if(name==="bezierinfo") {
document.getElementById('commentform').innerHTML = data; }}
// EasyPageComments handling
script = document.createElement("script");
script.onload = function() {
EasyPageComments.createCommentsList('bezierinfo');
EasyPageComments.createCommentForm('bezierinfo');
};
script.src = "js/EasyPageComments.js";
document.head.appendChild(script);
}
</script>
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
</div>
</body>
</html>