1
0
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:
Pomax
2020-08-04 11:06:54 -07:00
parent ce49ed985d
commit fec813773e
16 changed files with 709 additions and 150 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules
./en-GB
./zh-CN
./ja-JP

View File

81
chapters/toc.js Normal file
View 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
View 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
View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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(/&amp;/g, "&")
.replace(/&#39;/g, "'")
.replace(/&quot;/g, '"')
.replace(/<p>{{/g, `{{`)
.replace(/}}<\/p>/g, `}}`);
return nunjucks.renderString(converted, latex);
}
})();

View 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(/&amp;/g, "&")
.replace(/&#39;/g, "'")
.replace(/&quot;/g, '"')
.replace(/<p>{{/g, `{{`)
.replace(/}}<\/p>/g, `}}`);
return nunjucks.renderString(converted, latex);
}

View 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`);
}
};

View 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`);
};

View 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);
});
});
}

View File

@@ -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`);

View 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;
};

View File

@@ -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>