1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-09-02 21:02:49 +02:00

modules in sketch code

This commit is contained in:
Pomax
2020-08-14 10:51:19 -07:00
parent f7ec7fa90a
commit d8b8397326
17 changed files with 227 additions and 129 deletions

View File

@@ -1,56 +0,0 @@
# BezierInfo-2 ![CI-CD](https://github.com/Pomax/BezierInfo-2/workflows/CI-CD/badge.svg?branch=master)
Dev repository for https://Pomax.github.io/bezierinfo
## Working on the code
- To compile changes: `npm start`.
- To run this dev version, run `npm test`, which will run a webserver and open [http://localhost:8080](http://localhost:8080) in your default browser.
## Dev location
- Dev repository: https://github.com/Pomax/BezierInfo-2
- Dev preview: https://Pomax.github.io/BezierInfo-2
### Dev requirements
- [Node.js](https://nodejs.org)
- XeLaTeX (available through [TeXLive](https://www.tug.org/texlive) on unix/linux/OSX and [MiKTeX](https://miktex.org) on Windows)
- pdfcrop (available through [TeXLive](https://www.tug.org/texlive) on unix/linux/OSX and [MiKTeX](https://miktex.org) on Windows)
- The [`pdf2svg`](http://www.cityinthesky.co.uk/opensource/pdf2svg/) utility
### Fonts required for proper LaTeX typesetting
All fonts come with TeXLive and MiKTeX, and should be easy to install. Note that you will need the modern OpenType (otf/ttf) fonts, not the obsolete type1 fonts.
- en-GB fonts: TeX Gyre Pagella from the `tex-gyre` package
- ja-JP font: IPAex Mincho from the `ipaex` package (_not_ `ipaex-type1`)
- zh-CN font: Arhpic gbsn from the `arphic-ttf` package (_not_ `arphic`)
- maths fonts: TeX Gyre Pagella Math fonts from the `tex-gyre-math` package
### Running a build
As mentioned up top, run a build using `npm start`.
If you have all the prerequisites installed, this should "just work", although I can't make any guarantees on how long it will take: on my rather beefy workstation it takes around 85 seconds to run a build for all locales (`en-GB`, `zh-CN`, and `ja-JP`) when there are no new SVG images to generate.
## Main site location
- Main repository: https://github.com/Pomax/bezierInfo
- Main site: https://pomax.github.io/bezierInfo
## Localization
Interested in (helping with) localizing the Primer to your own language? That's awesome! Please read [the instructions on how to start localizing](https://github.com/Pomax/BezierInfo-2/wiki/localize) and please file issues if anything is unclear.
## Additional information
Interested in the actual architecture and tech stack? Read the blog post on how Webpack's sync processing and MathJAx's async processing were made to work together:
http://pomax.github.io/1451617530567/react-with-latex-without-needing-client-side-mathjax
And read about the tech choices made to enable localization in:
http://pomax.github.io/1489108158510/localization-is-hard
Finally, a fair number of people have helped by filing PRs for fixes for typos small and large over the years, all of whom are listed on the [contributors](https://github.com/Pomax/BezierInfo-2/graphs/contributors) page for this project. And a special thanks goes out to Simon Cozens who [went through the entire book](https://github.com/Pomax/BezierInfo-2/pulls?utf8=%E2%9C%93&q=is%3Apr+author%3Asimoncozens) to fix typos and phrasing.

View File

@@ -1,32 +0,0 @@
module.exports = {
setupQuadratic: function(api) {
var curve = api.getDefaultQuadratic();
api.setCurve(curve);
},
setupCubic: function(api) {
var curve = api.getDefaultCubic();
api.setCurve(curve);
},
draw: function(api, curve) {
api.reset();
api.drawSkeleton(curve);
var i,t,p,tg,n,m,nd=20;
for(i=0; i<=10; i++) {
t = i/10.0;
p = curve.get(t);
tg = curve.derivative(t);
m = Math.sqrt(tg.x*tg.x + tg.y*tg.y);
tg = {x:tg.x/m, y:tg.y/m};
n = curve.normal(t);
api.setColor("blue");
api.drawLine(p, {x:p.x+tg.x*nd, y:p.y+tg.y*nd});
api.setColor("red");
api.drawLine(p, {x:p.x+n.x*nd, y:p.y+n.y*nd});
api.setColor("black");
api.drawCircle(p,3);
}
}
};

View File

@@ -24,7 +24,7 @@ Let's unpack that a little:
And then we're done, we found "the" normal vector for a 3D curve. Let's see what that looks like for a sample curve, shall we? You can move your cursor across the graphic from left to right, to show the normal at a point with a t value that is based on your cursor position: all the way on the left is 0, all the way on the right = 1, midway is t=0.5, etc:
<Graphic title="Some known and unknown vectors" setup={this.setup} draw={this.drawFrenetVectors}/>
<graphics-element title="Some known and unknown vectors" src="./frenet.js"></graphics-element>
However, if you've played with that graphic a bit, you might have noticed something odd. The normal seems to "suddenly twist around" around between t=0.5 and t=0.75 - why is doing that?
@@ -109,7 +109,7 @@ Ignoring comments, this is certainly more code than when we were just computing
Speaking of better looking, what does this actually look like? Let's revisit that earlier curve, but this time use rotation minimising frames rather than Frenet frames:
<Graphic title="Æsthetically much better 3D curve normals" setup={this.setup} draw={this.drawRMFNormals}/>
<graphics-element title="Some known and unknown vectors" src="./rotation-minimizing.js"></graphics-element>
Now that looks much better!

View File

@@ -0,0 +1,9 @@
import { vectorlib } from "./vector-lib.js";
setup() {
// ...
}
draw() {
clear();
}

View File

@@ -0,0 +1,7 @@
setup() {
}
draw() {
clear();
}

View File

@@ -0,0 +1,72 @@
const vectorlib = {
normalize: function(v) {
let z = v.z || 0;
var d = Math.sqrt(v.x*v.x + v.y*v.y + z*z);
let r = { x:v.x/d, y:v.y/d };
if (v.z !== undefined) r.z = z/d;
return r;
},
vdot: function(v1, v2) {
let z1 = v1.z || 0;
let z2 = v2.z || 0;
return v1.x * v2.x + v1.y * v2.y + z1 * z2;
},
vscale: function(v, s) {
let r = {
x: s * v1.x,
y: s * v1.y
}
if (v.z !== undefined) {
r.z = s * v.z
}
return r;
},
vplus: function(v1, v2) {
let r = {
x: v1.x + v2.x,
y: v1.y + v2.y
};
if (v1.z !== undefined || v2.z !== undefined) {
r.z = (v1.z||0) + (v2.z||0);
};
return r;
},
vminus: function(v1, v2) {
let r = {
x: v1.x - v2.x,
y: v1.y - v2.y
};
if (v1.z !== undefined || v2.z !== undefined) {
r.z = (v1.z||0) - (v2.z||0);
};
return r;
},
vcross: function(v1, v2) {
if (v1.z === undefined || v2.z === undefined) {
throw new Error(`Cross product is not defined for 2D vectors.`);
}
return {
x: v1.y * v2.z - v1.z * v2.y,
y: v1.z * v2.x - v1.x * v2.z,
z: v1.x * v2.y - v1.y * v2.x
};
},
vlerp: function(t, v1, v2) {
let r = {
x: (1-t)*v1.x + t*v2.x,
y: (1-t)*v1.y + t*v2.y
};
if (v1.z !== undefined || v2.z !== undefined) {
r.z = (1-t)*(v1.z||0) + t*(v2.z||0);
};
return r;
}
};
export { vectorlib }

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -2727,11 +2727,22 @@ function drawCurve(points[], t):
position: all the way on the left is 0, all the way on the right =
1, midway is t=0.5, etc:
</p>
<Graphic
<graphics-element
title="Some known and unknown vectors"
setup="{this.setup}"
draw="{this.drawFrenetVectors}"
/>
width="275"
height="275"
src="./chapters/pointvectors3d/frenet.js"
>
<fallback-image>
<img
width="275px"
height="275px"
src="images\chapters\pointvectors3d\22cb6c545b8e25b55b0f415414ea53fa.png"
loading="lazy"
/>
Scripts are disabled. Showing fallback image.
</fallback-image></graphics-element
>
<p>
However, if you've played with that graphic a bit, you might have
@@ -2866,11 +2877,22 @@ function drawCurve(points[], t):
revisit that earlier curve, but this time use rotation minimising
frames rather than Frenet frames:
</p>
<Graphic
title="Æsthetically much better 3D curve normals"
setup="{this.setup}"
draw="{this.drawRMFNormals}"
/>
<graphics-element
title="Some known and unknown vectors"
width="275"
height="275"
src="./chapters/pointvectors3d/rotation-minimizing.js"
>
<fallback-image>
<img
width="275px"
height="275px"
src="images\chapters\pointvectors3d\259fa2934b1a09bcb02d6928019f3159.png"
loading="lazy"
/>
Scripts are disabled. Showing fallback image.
</fallback-image></graphics-element
>
<p>Now that looks much better!</p>
<p>

View File

@@ -2323,11 +2323,22 @@ function drawCurve(points[], t):
position: all the way on the left is 0, all the way on the right =
1, midway is t=0.5, etc:
</p>
<Graphic
<graphics-element
title="Some known and unknown vectors"
setup="{this.setup}"
draw="{this.drawFrenetVectors}"
/>
width="275"
height="275"
src="./chapters/pointvectors3d/frenet.js"
>
<fallback-image>
<img
width="275px"
height="275px"
src="images\chapters\pointvectors3d\22cb6c545b8e25b55b0f415414ea53fa.png"
loading="lazy"
/>
Scripts are disabled. Showing fallback image.
</fallback-image></graphics-element
>
<p>
However, if you've played with that graphic a bit, you might have
@@ -2462,11 +2473,22 @@ function drawCurve(points[], t):
revisit that earlier curve, but this time use rotation minimising
frames rather than Frenet frames:
</p>
<Graphic
title="Æsthetically much better 3D curve normals"
setup="{this.setup}"
draw="{this.drawRMFNormals}"
/>
<graphics-element
title="Some known and unknown vectors"
width="275"
height="275"
src="./chapters/pointvectors3d/rotation-minimizing.js"
>
<fallback-image>
<img
width="275px"
height="275px"
src="images\chapters\pointvectors3d\259fa2934b1a09bcb02d6928019f3159.png"
loading="lazy"
/>
Scripts are disabled. Showing fallback image.
</fallback-image></graphics-element
>
<p>Now that looks much better!</p>
<p>

View File

@@ -78,19 +78,20 @@ class GraphicsElement extends CustomElement {
* Load the graphics code, either from a src URL, a <program-code> element, or .textContent
*/
async loadSource() {
let src = false;
let codeElement = this.querySelector(`program-code`);
let code = ``;
if (codeElement) {
let src = codeElement.getAttribute("src");
src = codeElement.getAttribute("src");
if (src) {
code = await fetch(src).then((response) => response.text());
} else {
code = codeElement.textContent;
}
} else {
let src = this.getAttribute("src");
src = this.getAttribute("src");
if (src) {
code = await fetch(src).then((response) => response.text());
} else {
@@ -108,7 +109,7 @@ class GraphicsElement extends CustomElement {
new MutationObserver((_records) => {
// nornmally we don't want to completely recreate the shadow DOM
this.processSource(codeElement.textContent);
this.processSource(src, codeElement.textContent);
}).observe(codeElement, {
characterData: true,
attributes: false,
@@ -117,13 +118,13 @@ class GraphicsElement extends CustomElement {
});
// But on the first pass, we do.
this.processSource(code, true);
this.processSource(src, code, true);
}
/**
* Transform the graphics source code into global and class code.
*/
processSource(code, rerender = false) {
processSource(src, code, rerender = false) {
this.rawCode = code;
if (this.script) {
if (this.script.parentNode) {
@@ -136,6 +137,24 @@ class GraphicsElement extends CustomElement {
const uid = `bg-uid-${Date.now()}-${`${Math.random()}`.replace(`0.`, ``)}`;
window[uid] = this;
// Step 1: fix the imports. This is ... a bit of work.
let path;
let base = document.querySelector(`base`);
if (base) {
path = base.href;
} else {
let loc = window.location.toString();
path = loc.substring(0, loc.lastIndexOf(`/`) + 1);
}
let modulepath = `${path}${src}`;
let modulebase = modulepath.substring(0, modulepath.lastIndexOf(`/`) + 1);
// okay, I lied, it's actually quite a lot of work.
code = code.replace(/(import .+? from) "([^"]+)"/g, (_, main, group) => {
return `${main} "${modulebase}${group}"`;
});
// Then, step 2: split up the code into "global" vs. "class" code.
const split = splitCodeSections(code);
const globalCode = split.quasiGlobal;
const classCode = performCodeSurgery(split.classCode);

View File

@@ -10,7 +10,13 @@ const __root = path.join(__dirname, `..`, `..`, `..`);
/**
* ...docs go here...
*/
async function generateFallbackImage(localeStrings, src, width, height) {
async function generateFallbackImage(
chapter,
localeStrings,
src,
width,
height
) {
const locale = localeStrings.getCurrentLocale();
// Get the sketch code
@@ -35,7 +41,7 @@ async function generateFallbackImage(localeStrings, src, width, height) {
// If we get here, we need to actually run the magic: convert
// this to a valid JS module code and write this to a temporary
// file so we can import it.
const nodeCode = generateGraphicsModule(code, width, height);
const nodeCode = generateGraphicsModule(chapter, code, width, height);
const fileName = `./nodecode.${Date.now()}.${Math.random()}.js`;
const tempFile = path.join(__dirname, fileName);
fs.writeFileSync(tempFile, nodeCode, `utf8`);
@@ -45,7 +51,7 @@ async function generateFallbackImage(localeStrings, src, width, height) {
// turn into an actual image file.
const { canvas } = await import(fileName);
// fs.unlinkSync(tempFile);
fs.unlinkSync(tempFile);
// The canvas runs setup() + draw() as part of the module load, so
// all we have to do now is get the image data and writ it to file.

View File

@@ -5,7 +5,13 @@ import prettier from "prettier";
/**
* ...docs go here...
*/
function generateGraphicsModule(code, width, height) {
function generateGraphicsModule(chapter, code, width, height) {
// step 1: fix the imports
code = code.replace(/(import .+? from) "([^"]+)"/g, (_, main, group) => {
return `${main} "../../../chapters/${chapter}/${group}"`;
});
// step 2: split up the code into "global" vs. "class" code
const split = splitCodeSections(code);
const globalCode = split.quasiGlobal;
const classCode = performCodeSurgery(split.classCode);
@@ -15,10 +21,10 @@ function generateGraphicsModule(code, width, height) {
import CanvasBuilder from 'canvas';
import { GraphicsAPI, Bezier, Vector, Matrix } from "../../../lib/custom-element/api/graphics-api.js";
const noop = (()=>{});
${globalCode}
const noop = (()=>{});
class Example extends GraphicsAPI { ${classCode} }
const example = new Example(undefined, ${width}, ${height}, (w,h) => {

View File

@@ -52,6 +52,7 @@ async function preprocessGraphicsElement(chapter, localeStrings, markdown) {
}
let imageHash = await generateFallbackImage(
chapter,
localeStrings,
src,
width,

View File

@@ -77,7 +77,7 @@ async function processLocale(locale, localeStrings, chapterFiles) {
}
const end = Date.now();
// console.log(`Processing ${locale} took ${(end - start) / 1000}s`);
console.log(`Processing ${locale} took ${(end - start) / 1000}s`);
return chapters;
}

View File

@@ -2333,11 +2333,22 @@ function drawCurve(points[], t):
position: all the way on the left is 0, all the way on the right =
1, midway is t=0.5, etc:
</p>
<Graphic
<graphics-element
title="Some known and unknown vectors"
setup="{this.setup}"
draw="{this.drawFrenetVectors}"
/>
width="275"
height="275"
src="./chapters/pointvectors3d/frenet.js"
>
<fallback-image>
<img
width="275px"
height="275px"
src="images\chapters\pointvectors3d\22cb6c545b8e25b55b0f415414ea53fa.png"
loading="lazy"
/>
Scripts are disabled. Showing fallback image.
</fallback-image></graphics-element
>
<p>
However, if you've played with that graphic a bit, you might have
@@ -2472,11 +2483,22 @@ function drawCurve(points[], t):
revisit that earlier curve, but this time use rotation minimising
frames rather than Frenet frames:
</p>
<Graphic
title="Æsthetically much better 3D curve normals"
setup="{this.setup}"
draw="{this.drawRMFNormals}"
/>
<graphics-element
title="Some known and unknown vectors"
width="275"
height="275"
src="./chapters/pointvectors3d/rotation-minimizing.js"
>
<fallback-image>
<img
width="275px"
height="275px"
src="images\chapters\pointvectors3d\259fa2934b1a09bcb02d6928019f3159.png"
loading="lazy"
/>
Scripts are disabled. Showing fallback image.
</fallback-image></graphics-element
>
<p>Now that looks much better!</p>
<p>