mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-08-31 20:11:59 +02:00
better building
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
./en-GB
|
||||
./zh-CN
|
||||
./ja-JP
|
81
chapters/toc.js
Normal file
81
chapters/toc.js
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* This is an ordered list of all sections used in the Bezier primer.
|
||||
*
|
||||
* The ordering you see here reflects the ordering in which sections
|
||||
'* are present on the Primer page',
|
||||
* a REALLY good reason to =)
|
||||
*
|
||||
*/
|
||||
module.exports = [
|
||||
'preface',
|
||||
|
||||
// the basic topic(s) introduction(s)
|
||||
'introduction',
|
||||
'whatis',
|
||||
'explanation',
|
||||
'control',
|
||||
'weightcontrol',
|
||||
'extended',
|
||||
|
||||
// basic operations
|
||||
'matrix',
|
||||
'decasteljau',
|
||||
'flattening',
|
||||
'splitting',
|
||||
'matrixsplit',
|
||||
'reordering',
|
||||
|
||||
// information that can be obtained through analysis
|
||||
'derivatives',
|
||||
'pointvectors',
|
||||
'pointvectors3d',
|
||||
'components',
|
||||
'extremities',
|
||||
'boundingbox',
|
||||
'aligning',
|
||||
'tightbounds',
|
||||
'inflections',
|
||||
'canonical',
|
||||
'yforx',
|
||||
|
||||
// accurate arc length is hard, yo
|
||||
'arclength',
|
||||
'arclengthapprox',
|
||||
'curvature',
|
||||
'tracing',
|
||||
|
||||
// curve intersections
|
||||
'intersections',
|
||||
'curveintersection',
|
||||
|
||||
// curve manipulation
|
||||
'abc',
|
||||
'moulding',
|
||||
'pointcurves',
|
||||
'curvefitting',
|
||||
|
||||
// A quick foray into Catmull-Rom splines
|
||||
'catmullconv',
|
||||
'catmullmoulding',
|
||||
|
||||
// "things made of more than on curve"
|
||||
'polybezier',
|
||||
'shapes',
|
||||
// 'drawing',
|
||||
|
||||
// curve offsetting
|
||||
'projections',
|
||||
'offsetting',
|
||||
'graduatedoffset',
|
||||
|
||||
// circle and arc approximation
|
||||
'circles',
|
||||
'circles_cubic',
|
||||
'arcapproximation',
|
||||
|
||||
// A quick foray in to B-Spline land
|
||||
'bsplines',
|
||||
|
||||
// comments come last for obvious reasons
|
||||
'comments',
|
||||
];
|
18
config.json
Normal file
18
config.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"defaultLocale": "en-GB",
|
||||
"localeName": {
|
||||
"en-GB": "English",
|
||||
"zh-CN": "中文",
|
||||
"ja-JP": "日本語"
|
||||
},
|
||||
"langSwitchLabel": {
|
||||
"en-GB": "Read this in your own language:",
|
||||
"zh-CN": "Read this in your own language:",
|
||||
"ja-JP": "Read this in your own language:"
|
||||
},
|
||||
"disabledMessage": {
|
||||
"en-GB": "Scripts are disabled. Showing fallback image.",
|
||||
"zh-CN": "脚本已禁用,并显示后备图像。",
|
||||
"ja-JP": "JSがなくて、画像を表示しています。"
|
||||
}
|
||||
}
|
209
en-GB/index.html
Normal file
209
en-GB/index.html
Normal file
@@ -0,0 +1,209 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<title>A Primer on Bézier Curves</title>
|
||||
<link rel="shortcut icon" href="favicon.png" type="image/png" />
|
||||
|
||||
<base href=".." />
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="A Primer on Bézier Curves" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://pomax.github.io/bezierinfo/images/og-image.png"
|
||||
/>
|
||||
<meta property="og:type" content="text" />
|
||||
<meta property="og:url" content="https://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 Curves" />
|
||||
|
||||
<!-- my own referral/page hit tracker -->
|
||||
<script src="./lib/site/referrer.js" type="module" async></script>
|
||||
|
||||
<!-- the part that makes interactive graphics work: an HTML5 <graphics-element> custom element -->
|
||||
<script
|
||||
src="./lib/custom-element/graphics-element.js"
|
||||
type="module"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<link rel="stylesheet" href="./lib/custom-element/graphics-element.css" />
|
||||
|
||||
<!-- page styling -->
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1>A Primer on Bézier Curves</h1>
|
||||
<h2>
|
||||
A free, online book for when you really need to know how to do Bézier
|
||||
things.
|
||||
</h2>
|
||||
<span>Read this in your own language:</span>
|
||||
<ul>
|
||||
<li><a href="../en-GB/index.html">English</a></li>
|
||||
<li><a href="../ja-JP/index.html">日本語</a></li>
|
||||
<li><a href="../zh-CN/index.html">中文</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section id="preface"></section>
|
||||
|
||||
<section id="toc">
|
||||
<ol>
|
||||
<li><a href="#introduction">A lightning introduction</a></li>
|
||||
<li><a href="#whatis">So what makes a Bézier Curve?</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section id="changelog"></section>
|
||||
|
||||
<section id="chapters">
|
||||
<section id="introduction">
|
||||
<h1>A lightning introduction</h1>
|
||||
<p>
|
||||
Let's start with the good stuff: when we're talking about Bézier
|
||||
curves, we're talking about the things that you can see in the
|
||||
following graphics. They run from some start point to some end
|
||||
point, with their curvature influenced by one or more "intermediate"
|
||||
control points. Now, because all the graphics on this page are
|
||||
interactive, go manipulate those curves a bit: click-drag the
|
||||
points, and see how their shape changes based on what you do.
|
||||
</p>
|
||||
<div class="figure">
|
||||
<graphics-element
|
||||
title="Quadratic Bézier curves"
|
||||
width="200"
|
||||
height="200"
|
||||
src="./chapters/introduction/quadratic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
src="./chapters/introduction/quadratic.png"
|
||||
width="200"
|
||||
height="200"
|
||||
/>
|
||||
<span>Scripts are disabled. Showing fallback image.</span>
|
||||
</fallback-image>
|
||||
</graphics-element>
|
||||
|
||||
<graphics-element
|
||||
title="Cubic Bézier curves"
|
||||
width="200"
|
||||
height="200"
|
||||
src="./chapters/introduction/cubic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
src="./chapters/introduction/cubic.png"
|
||||
width="200"
|
||||
height="200"
|
||||
/>
|
||||
<span>Scripts are disabled. Showing fallback image.</span>
|
||||
</fallback-image>
|
||||
</graphics-element>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
These curves are used a lot in computer aided design and computer
|
||||
aided manufacturing (CAD/CAM) applications, as well as in graphic
|
||||
design programs like Adobe Illustrator and Photoshop, Inkscape,
|
||||
GIMP, etc. and in graphic technologies like scalable vector graphics
|
||||
(SVG) and OpenType fonts (TTF/OTF). A lot of things use Bézier
|
||||
curves, so if you want to learn more about them... prepare to get
|
||||
your learn on!
|
||||
</p>
|
||||
</section>
|
||||
<section id="whatis">
|
||||
<h1>So what makes a Bézier Curve?</h1>
|
||||
<p>
|
||||
Playing with the points for curves may have given you a feel for how
|
||||
Bézier curves behave, but what <em>are</em> 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:
|
||||
</p>
|
||||
<p>
|
||||
Bézier curves are the result of
|
||||
<a href="https://en.wikipedia.org/wiki/Linear_interpolation"
|
||||
>linear interpolations</a
|
||||
>. 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".
|
||||
</p>
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
<img
|
||||
className="LaTeX SVG"
|
||||
src="images/latex/0ee04e4056391f945c1c21c1174a03b5.svg"
|
||||
width="507px"
|
||||
height="103px"
|
||||
/>
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Linear Interpolation leading to Bézier curves"
|
||||
width="200"
|
||||
height="200"
|
||||
src="./chapters/whatis/interpolation.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img src="./chapters/whatis/interpolation.png" />
|
||||
<span>Scripts are disabled. Showing fallback image.</span>
|
||||
</fallback-image>
|
||||
</graphics-element>
|
||||
|
||||
<p>And that brings us to the complicated maths: calculus.</p>
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<!-- ...code goes here... -->
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@@ -49,6 +49,12 @@
|
||||
A free, online book for when you really need to know how to do Bézier
|
||||
things.
|
||||
</h2>
|
||||
<span>Read this in your own language:</span>
|
||||
<ul>
|
||||
<li><a href="./index.html">English</a></li>
|
||||
<li><a href="ja-JP/index.html">日本語</a></li>
|
||||
<li><a href="zh-CN/index.html">中文</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<main>
|
@@ -8,6 +8,8 @@
|
||||
<title>A Primer on Bézier Curves</title>
|
||||
<link rel="shortcut icon" href="favicon.png" type="image/png">
|
||||
|
||||
{{ base }}
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="A Primer on Bézier Curves">
|
||||
<meta property="og:image" content="https://pomax.github.io/bezierinfo/images/og-image.png">
|
||||
@@ -37,6 +39,8 @@
|
||||
<header>
|
||||
<h1>A Primer on Bézier Curves</h1>
|
||||
<h2>A free, online book for when you really need to know how to do Bézier things.</h2>
|
||||
<span>{{ langSwitchLabel }}</span>
|
||||
<ul>{{ langSwitcher }}</ul>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
@@ -7,6 +7,8 @@
|
||||
<title>A Primer on Bézier Curves</title>
|
||||
<link rel="shortcut icon" href="favicon.png" type="image/png" />
|
||||
|
||||
<base href=".." />
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="A Primer on Bézier Curves" />
|
||||
<meta
|
||||
@@ -49,6 +51,12 @@
|
||||
A free, online book for when you really need to know how to do Bézier
|
||||
things.
|
||||
</h2>
|
||||
<span>Read this in your own language:</span>
|
||||
<ul>
|
||||
<li><a href="../index.html">English</a></li>
|
||||
<li><a href="../ja-JP/index.html">日本語</a></li>
|
||||
<li><a href="../zh-CN/index.html">中文</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
@@ -57,6 +65,7 @@
|
||||
<section id="toc">
|
||||
<ol>
|
||||
<li><a href="#introduction">バッとした導入</a></li>
|
||||
<li><a href="#whatis">So what makes a Bézier Curve?</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
@@ -110,6 +119,78 @@
|
||||
graphics)・OpenTypeフォント(otf/ttf)のようなグラフィック技術でも利用されています。ベジエ曲線はたくさんのものに使われていますので、これについてもっと詳しく学びたいのであれば……さあ、準備しましょう!
|
||||
</p>
|
||||
</section>
|
||||
<section id="whatis">
|
||||
<h1>So what makes a Bézier Curve?</h1>
|
||||
<p>
|
||||
Playing with the points for curves may have given you a feel for how
|
||||
Bézier curves behave, but what <em>are</em> 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:
|
||||
</p>
|
||||
<p>
|
||||
Bézier curves are the result of
|
||||
<a href="https://en.wikipedia.org/wiki/Linear_interpolation"
|
||||
>linear interpolations</a
|
||||
>. 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".
|
||||
</p>
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
<img
|
||||
className="LaTeX SVG"
|
||||
src="images/latex/0ee04e4056391f945c1c21c1174a03b5.svg"
|
||||
width="507px"
|
||||
height="103px"
|
||||
/>
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Linear Interpolation leading to Bézier curves"
|
||||
width="200"
|
||||
height="200"
|
||||
src="./chapters/whatis/interpolation.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img src="./chapters/whatis/interpolation.png" />
|
||||
<span>JSがなくて、画像を表示しています。</span>
|
||||
</fallback-image>
|
||||
</graphics-element>
|
||||
|
||||
<p>And that brings us to the complicated maths: calculus.</p>
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
|
@@ -25,158 +25,23 @@
|
||||
**********************************************************************/
|
||||
|
||||
const fs = require("fs-extra");
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
const marked = require("marked");
|
||||
const prettier = require("prettier");
|
||||
const latexToSVG = require("./latex-to-svg");
|
||||
|
||||
const nunjucks = require("nunjucks");
|
||||
nunjucks.configure(".", { autoescape: false });
|
||||
|
||||
// make sure we know what our base location is
|
||||
const BASEDIR = path.join(__dirname, "..");
|
||||
|
||||
// bundle all content in a specific locale for use by the app
|
||||
const defaultLocale = "en-GB";
|
||||
var locale = defaultLocale;
|
||||
var lpos = process.argv.indexOf("--locale");
|
||||
if (lpos !== -1) locale = process.argv[lpos + 1];
|
||||
const getAllChapterFiles = require("./build/get-all-chapter-files.js");
|
||||
const processLocale = require("./build/process-locale.js");
|
||||
const createIndexPages = require("./build/create-index-page.js");
|
||||
|
||||
// main entry point
|
||||
|
||||
(async function () {
|
||||
const locales = await findLocales();
|
||||
Object.keys(locales).forEach(async (locale) => {
|
||||
const chapters = await processLocale(locale, locales[locale]);
|
||||
createIndexPages(locale, chapters);
|
||||
const chapterFiles = await getAllChapterFiles();
|
||||
const languageCodes = Object.keys(chapterFiles);
|
||||
const sectionList = fs
|
||||
.readdirSync(`chapters`)
|
||||
.filter((v) => v.indexOf(`.`) === -1)
|
||||
.map((v) => path.posix.join(__dirname.split(path.sep).join(path.posix.sep), `..`, `chapters`, v));
|
||||
languageCodes.forEach(async (locale) => {
|
||||
const chapters = await processLocale(locale, chapterFiles, sectionList);
|
||||
createIndexPages(locale, chapters, languageCodes);
|
||||
});
|
||||
})();
|
||||
|
||||
// functions
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
function findLocales() {
|
||||
return new Promise((resolve, reject) => {
|
||||
glob(path.join(BASEDIR, `chapters/**/content*md`), (err, files) => {
|
||||
if (err) reject(err);
|
||||
|
||||
const locales = {};
|
||||
|
||||
files.forEach((file) => {
|
||||
let locale = file.match(/content\.([^.]+)\.md/)[1];
|
||||
if (!locales[locale]) {
|
||||
locales[locale] = [];
|
||||
}
|
||||
locales[locale].push(file);
|
||||
});
|
||||
|
||||
resolve(locales);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
async function processLocale(locale, files) {
|
||||
const chapters = {};
|
||||
|
||||
await Promise.all(
|
||||
files.map(async (file) => {
|
||||
const chapter = file.match(/chapters\/([^/]+)\/content./)[1];
|
||||
const markdown = fs.readFileSync(file).toString("utf8");
|
||||
const replaced = nunjucks.renderString(markdown, {
|
||||
disableMessage: `<span>${getDisabledMessage(locale)}</span>`,
|
||||
});
|
||||
const converted = await convertMarkDown(replaced);
|
||||
chapters[chapter] = converted;
|
||||
})
|
||||
);
|
||||
|
||||
return chapters;
|
||||
}
|
||||
|
||||
/**
|
||||
* ...docs go here
|
||||
*/
|
||||
function getDisabledMessage(locale) {
|
||||
const localizedMessages = {
|
||||
"en-GB": `Scripts are disabled. Showing fallback image.`,
|
||||
"zh-CN": `脚本已禁用,并显示后备图像。`,
|
||||
"ja-JP": `JSがなくて、画像を表示しています。`,
|
||||
};
|
||||
return localizedMessages[locale];
|
||||
}
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
async function createIndexPages(locale, chapters) {
|
||||
const toc = {};
|
||||
const sections = Object.keys(chapters).map((section) => {
|
||||
let content = chapters[section];
|
||||
toc[section] = content.match(/<h1>([^<]+)<\/h1>/)[1];
|
||||
return `<section id="${section}">\n${content}</section>`;
|
||||
});
|
||||
|
||||
const index = nunjucks.render(`index.template.html`, {
|
||||
locale,
|
||||
toc: Object.keys(toc)
|
||||
.map((id) => `<li><a href="#${id}">${toc[id]}</a></li>`)
|
||||
.join(`\n`),
|
||||
chapters: sections.join(`\n`),
|
||||
});
|
||||
|
||||
const data = prettier.format(index, { parser: `html` });
|
||||
fs.writeFileSync(`index.${locale}.html`, data, `utf8`);
|
||||
}
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
async function convertMarkDown(markdown) {
|
||||
// preprocess marrkdown to extract LaTeX sections
|
||||
let latexSection = 0,
|
||||
pos = -1,
|
||||
data = markdown,
|
||||
latex = [],
|
||||
startmark = `<script type="text/latex">`,
|
||||
endmark = `</script>`;
|
||||
|
||||
do {
|
||||
pos = data.indexOf(startmark);
|
||||
if (pos !== -1) {
|
||||
let endpos = data.indexOf(endmark, pos) + endmark.length;
|
||||
let key = `latex${latexSection}`;
|
||||
latex[key] = data.substring(
|
||||
pos + startmark.length,
|
||||
endpos - endmark.length
|
||||
);
|
||||
data = `${data.slice(0, pos)}{{ ${key} }}${data.slice(endpos)}`;
|
||||
}
|
||||
} while (pos !== -1);
|
||||
|
||||
await Promise.all(
|
||||
Object.keys(latex).map(async (key) => {
|
||||
const svg = await latexToSVG(latex[key]);
|
||||
return (latex[key] = svg);
|
||||
})
|
||||
);
|
||||
|
||||
let converted = marked(data, {
|
||||
gfm: true,
|
||||
headerIds: false,
|
||||
mangle: false,
|
||||
})
|
||||
// sigh...
|
||||
.replace(/&/g, "&")
|
||||
.replace(/'/g, "'")
|
||||
.replace(/"/g, '"')
|
||||
.replace(/<p>{{/g, `{{`)
|
||||
.replace(/}}<\/p>/g, `}}`);
|
||||
|
||||
return nunjucks.renderString(converted, latex);
|
||||
}
|
||||
})();
|
52
tools/build/convert-markdown.js
Normal file
52
tools/build/convert-markdown.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const marked = require("marked");
|
||||
const latexToSVG = require("./latex-to-svg");
|
||||
const nunjucks = require("nunjucks");
|
||||
nunjucks.configure(".", { autoescape: false });
|
||||
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
module.exports = async function convertMarkDown(markdown) {
|
||||
// preprocess marrkdown to extract LaTeX sections
|
||||
let latexSection = 0,
|
||||
pos = -1,
|
||||
data = markdown,
|
||||
latex = [],
|
||||
startmark = `<script type="text/latex">`,
|
||||
endmark = `</script>`;
|
||||
|
||||
do {
|
||||
pos = data.indexOf(startmark);
|
||||
if (pos !== -1) {
|
||||
let endpos = data.indexOf(endmark, pos) + endmark.length;
|
||||
let key = `latex${latexSection}`;
|
||||
latex[key] = data.substring(
|
||||
pos + startmark.length,
|
||||
endpos - endmark.length
|
||||
);
|
||||
data = `${data.slice(0, pos)}{{ ${key} }}${data.slice(endpos)}`;
|
||||
}
|
||||
} while (pos !== -1);
|
||||
|
||||
await Promise.all(
|
||||
Object.keys(latex).map(async (key) => {
|
||||
const svg = await latexToSVG(latex[key]);
|
||||
return (latex[key] = svg);
|
||||
})
|
||||
);
|
||||
|
||||
let converted = marked(data, {
|
||||
gfm: true,
|
||||
headerIds: false,
|
||||
mangle: false,
|
||||
})
|
||||
// sigh...
|
||||
.replace(/&/g, "&")
|
||||
.replace(/'/g, "'")
|
||||
.replace(/"/g, '"')
|
||||
.replace(/<p>{{/g, `{{`)
|
||||
.replace(/}}<\/p>/g, `}}`);
|
||||
|
||||
return nunjucks.renderString(converted, latex);
|
||||
}
|
50
tools/build/create-index-page.js
Normal file
50
tools/build/create-index-page.js
Normal file
@@ -0,0 +1,50 @@
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
const config = require("../../config.json");
|
||||
const defaultLocale = config.defaultLocale
|
||||
const prettier = require("prettier");
|
||||
const generateLangSwitcher = require("./generate-lang-switcher.js");
|
||||
const nunjucks = require("nunjucks");
|
||||
|
||||
nunjucks.configure(".", { autoescape: false });
|
||||
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
module.exports = async function createIndexPages(locale, chapters, languages) {
|
||||
let base = ``;
|
||||
|
||||
if (locale !== defaultLocale) {
|
||||
base = `<base href="..">`;
|
||||
}
|
||||
|
||||
const langSwitcher = generateLangSwitcher(locale, languages, defaultLocale);
|
||||
|
||||
const toc = {};
|
||||
|
||||
const sections = Object.keys(chapters).map((section) => {
|
||||
let content = chapters[section];
|
||||
let title = content.match(/<h1>([^<]+)<\/h1>/)[1];
|
||||
toc[section] = `<li><a href="#${section}">${title}</a></li>`;
|
||||
return `<section id="${section}">\n${content}</section>`;
|
||||
});
|
||||
|
||||
const index = nunjucks.render(`index.template.html`, {
|
||||
base,
|
||||
locale,
|
||||
langSwitchLabel: config.langSwitchLabel[locale],
|
||||
langSwitcher,
|
||||
toc: Object.values(toc).join(`\n`),
|
||||
chapters: sections.join(`\n`),
|
||||
});
|
||||
|
||||
const data = prettier.format(index, { parser: `html` });
|
||||
|
||||
if (locale === defaultLocale) {
|
||||
fs.writeFileSync(`index.html`, data, `utf8`);
|
||||
} else {
|
||||
fs.ensureDir(locale);
|
||||
fs.writeFileSync(path.join(locale, `index.html`), data, `utf8`);
|
||||
}
|
||||
};
|
25
tools/build/generate-lang-switcher.js
Normal file
25
tools/build/generate-lang-switcher.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const config = require("../../config.json");
|
||||
const defaultLocale = config.defaultLocale
|
||||
|
||||
|
||||
module.exports = function generateLangSwitcher(currentLocale, allLocales) {
|
||||
return allLocales
|
||||
.map((locale) => {
|
||||
let link;
|
||||
if (currentLocale === defaultLocale) {
|
||||
if (locale === defaultLocale) {
|
||||
link = `./index.html`;
|
||||
} else {
|
||||
link = `${locale}/index.html`;
|
||||
}
|
||||
} else {
|
||||
if (locale === defaultLocale) {
|
||||
link = `../index.html`;
|
||||
} else {
|
||||
link = `../${locale}/index.html`;
|
||||
}
|
||||
}
|
||||
return `<li><a href="${link}">${config.localeName[locale]}</a></li>`;
|
||||
})
|
||||
.join(`\n`);
|
||||
};
|
29
tools/build/get-all-chapter-files.js
Normal file
29
tools/build/get-all-chapter-files.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const fs = require("fs-extra");
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
|
||||
// make sure we know what our base location is
|
||||
const BASEDIR = path.join(__dirname, "..", "..");
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
module.exports = function getAllChapterFiles() {
|
||||
return new Promise((resolve, reject) => {
|
||||
glob(path.join(BASEDIR, `chapters/**/content*md`), (err, files) => {
|
||||
if (err) reject(err);
|
||||
|
||||
const locales = {};
|
||||
|
||||
files.forEach((file) => {
|
||||
let locale = file.match(/content\.([^.]+)\.md/)[1];
|
||||
if (!locales[locale]) {
|
||||
locales[locale] = [];
|
||||
}
|
||||
locales[locale].push(file);
|
||||
});
|
||||
|
||||
resolve(locales);
|
||||
});
|
||||
});
|
||||
}
|
@@ -1,10 +1,10 @@
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
const crypto = require("crypto");
|
||||
const cleanUp = require("./cleanup");
|
||||
const cleanUp = require("../cleanup");
|
||||
const execSync = require("child_process").execSync;
|
||||
|
||||
const baseDir = path.join(__dirname, `..`, `images`, `latex`);
|
||||
const baseDir = path.join(__dirname, `..`, `..`, `images`, `latex`);
|
||||
fs.ensureDirSync(baseDir);
|
||||
|
||||
const sourceDir = path.join(baseDir, `source`);
|
54
tools/build/process-locale.js
Normal file
54
tools/build/process-locale.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
const config = require("../../config.json");
|
||||
const defaultLocale = config.defaultLocale
|
||||
const convertMarkDown = require("./convert-markdown.js");
|
||||
const nunjucks = require("nunjucks");
|
||||
|
||||
nunjucks.configure(".", { autoescape: false });
|
||||
|
||||
|
||||
/**
|
||||
* ...docs go here...
|
||||
*/
|
||||
module.exports = async function processLocale(
|
||||
locale,
|
||||
chapterFiles,
|
||||
sectionList
|
||||
) {
|
||||
const localeFiles = chapterFiles[locale];
|
||||
let localized = 0;
|
||||
|
||||
// make sure we fall back to en-GB content if there is no localised version
|
||||
sectionList.forEach((chapterpath) => {
|
||||
if (localeFiles.every((file) => file.indexOf(chapterpath) === -1)) {
|
||||
localeFiles.push(
|
||||
path.posix.join(chapterpath, `content.${defaultLocale}.md`)
|
||||
);
|
||||
} else {
|
||||
localized++;
|
||||
}
|
||||
});
|
||||
|
||||
if (localized < sectionList.length) {
|
||||
console.log(`${locale} partially localized: [${localized}/${sectionList.length}]`)
|
||||
} else {
|
||||
console.log(`${locale} fully localized.`)
|
||||
}
|
||||
|
||||
const chapters = {};
|
||||
|
||||
await Promise.all(
|
||||
localeFiles.map(async (file) => {
|
||||
const chapter = file.match(/chapters\/([^/]+)\/content./)[1];
|
||||
const markdown = fs.readFileSync(file).toString("utf8");
|
||||
const replaced = nunjucks.renderString(markdown, {
|
||||
disableMessage: `<span>${config.disabledMessage[locale]}</span>`,
|
||||
});
|
||||
const converted = await convertMarkDown(replaced);
|
||||
chapters[chapter] = converted;
|
||||
})
|
||||
);
|
||||
|
||||
return chapters;
|
||||
};
|
@@ -7,6 +7,8 @@
|
||||
<title>A Primer on Bézier Curves</title>
|
||||
<link rel="shortcut icon" href="favicon.png" type="image/png" />
|
||||
|
||||
<base href=".." />
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="A Primer on Bézier Curves" />
|
||||
<meta
|
||||
@@ -49,6 +51,12 @@
|
||||
A free, online book for when you really need to know how to do Bézier
|
||||
things.
|
||||
</h2>
|
||||
<span>Read this in your own language:</span>
|
||||
<ul>
|
||||
<li><a href="../index.html">English</a></li>
|
||||
<li><a href="../ja-JP/index.html">日本語</a></li>
|
||||
<li><a href="../zh-CN/index.html">中文</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
@@ -57,6 +65,7 @@
|
||||
<section id="toc">
|
||||
<ol>
|
||||
<li><a href="#introduction">简单介绍</a></li>
|
||||
<li><a href="#whatis">So what makes a Bézier Curve?</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
@@ -108,6 +117,78 @@
|
||||
Gimp等等。还可以应用在一些图形技术中,像矢量图形(SVG)和OpenType字体(ttf/otf)。许多东西都用到贝塞尔曲线,如果你想更了解它们...准备好继续往下学吧!
|
||||
</p>
|
||||
</section>
|
||||
<section id="whatis">
|
||||
<h1>So what makes a Bézier Curve?</h1>
|
||||
<p>
|
||||
Playing with the points for curves may have given you a feel for how
|
||||
Bézier curves behave, but what <em>are</em> 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:
|
||||
</p>
|
||||
<p>
|
||||
Bézier curves are the result of
|
||||
<a href="https://en.wikipedia.org/wiki/Linear_interpolation"
|
||||
>linear interpolations</a
|
||||
>. 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".
|
||||
</p>
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
<img
|
||||
className="LaTeX SVG"
|
||||
src="images/latex/0ee04e4056391f945c1c21c1174a03b5.svg"
|
||||
width="507px"
|
||||
height="103px"
|
||||
/>
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Linear Interpolation leading to Bézier curves"
|
||||
width="200"
|
||||
height="200"
|
||||
src="./chapters/whatis/interpolation.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img src="./chapters/whatis/interpolation.png" />
|
||||
<span>脚本已禁用,并显示后备图像。</span>
|
||||
</fallback-image>
|
||||
</graphics-element>
|
||||
|
||||
<p>And that brings us to the complicated maths: calculus.</p>
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
|
Reference in New Issue
Block a user