SetMiter; PenScale

This commit is contained in:
Tony Garnock-Jones 2023-02-14 14:52:46 +01:00
parent 7d1f6fe249
commit 1737848330
2 changed files with 71 additions and 40 deletions

View File

@ -106,7 +106,7 @@
; >>>>> ; >>>>>
<sprite "tt2" [] <sprite "tt2" []
<move <v 0.0 1.6 3.0> <move <v 0.0 1.6 5.2>
<color 0.5 0.0 1.0 <color 0.5 0.0 1.0
<turtle [ <turtle [
1 to slen 1 to slen
@ -128,29 +128,46 @@
]>>>> ]>>>>
<sprite "tt" [] <sprite "tt" []
<move <v 1.0 0.01 0.75> <move <v 1.0 1.01 0.75>
<rotate <v -0.125 0.0 0.0> <rotate <v -0.125 0.0 0.0>
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg" <texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<v 2.0 1.0> <v 2.0 1.0>
<v 0.0 0.0> <v 0.0 0.0>
1.0] 1.0]
<turtle [ <csg
1.0 to wallHeight <subtract [
0.1 to wallDepth <mesh
<turtle [
1.0 to wallHeight
0.1 to wallDepth
90 U 90 U
PenDown PenDown
[wallHeight F 90 L wallDepth F 90 L] 2 times [wallHeight F 90 L wallDepth F 90 L] 2 times
SetPen SetPen
Home Home
[ 1 to k k / [dup F] k times drop ] to ff #t SetMiter
[ 2 / dup R 0 F R 0 F ] to rr ; #t SetSmooth
PenDown ; quote F to ff
1 ff 90 rr 1 ff 90 rr 1 ff 90 rr 1 ff 90 rr [ 1 to k k / [dup F] k times drop ] to ff
PenUp
]>>>>> [ R 0 F ] to rr
; [ R 0 F 60 D ] to rr
; [ 4 to k k / [dup R 0 F] k times drop ] to rr
PenDown
60 to sides
[4 sides / ff 360 sides / rr] sides 2 / 2 - times
1 0.5 1 PenScale 0 F
[4 sides / ff 360 sides / rr] 4 times
1 1 1 PenScale 0 F
[4 sides / ff 360 sides / rr] sides 2 / 2 - times
PenUp
]>>
<mesh <box>>
]>>>>>>
; <Exit "y" "lobby"> ; <Exit "y" "lobby">
; <sprite "y" [] ; <sprite "y" []

View File

@ -14,6 +14,8 @@ import * as Cat from './cat.js';
export class PenState { export class PenState {
templatePath: Vector3[] = [new Vector3()]; templatePath: Vector3[] = [new Vector3()];
paths: Vector3[][] | null = null; paths: Vector3[][] | null = null;
directions: Quaternion[] | null = null;
templateScale = new Vector3(1, 1, 1);
get isDown(): boolean { get isDown(): boolean {
return this.paths !== null; return this.paths !== null;
@ -22,27 +24,43 @@ export class PenState {
clear() { clear() {
this.templatePath = [new Vector3()]; this.templatePath = [new Vector3()];
this.paths = null; this.paths = null;
this.directions = null;
} }
set() { set() {
if (!this.paths) throw new Error("Cannot set pen with no paths"); if (!this.paths) throw new Error("Cannot set pen with no paths");
this.templatePath = this.paths[0]; this.templatePath = this.paths[0];
this.paths = null; this.paths = null;
this.directions = null;
} }
down() { down() {
this.paths = this.templatePath.map(_p => []); this.paths = this.templatePath.map(_p => []);
this.directions = [];
} }
push(pos: Vector3, q: Quaternion) { push(pos: Vector3, q: Quaternion, miter: boolean) {
const directions = this.directions!;
const paths = this.paths!;
if (miter && directions.length > 0) {
const lastQ = directions[directions.length - 1];
const lastDir = new Vector3(0, 0, 1).applyRotationQuaternionInPlace(lastQ);
const thisDir = new Vector3(0, 0, 1).applyRotationQuaternionInPlace(q);
const miterDir = lastDir.add(thisDir).normalize();
const miterPlane = Plane.FromPositionAndNormal(pos, miterDir);
for (let pathIndex = 0; pathIndex < paths.length; pathIndex++) {
const steps = paths[pathIndex];
const p = steps[steps.length - 1];
steps[steps.length - 1] = p.add(lastDir.scale(new Ray(p, lastDir).intersectsPlane(miterPlane)!));
}
}
this.templatePath.forEach((p, i) => { this.templatePath.forEach((p, i) => {
const r = new Vector3(); paths[i].push(p.multiply(this.templateScale).applyRotationQuaternion(q).addInPlace(pos));
// p.multiplyToRef(this.templateScale, r);
// r.rotateByQuaternionToRef(q, r);
p.rotateByQuaternionToRef(q, r);
r.addInPlace(pos);
this.paths![i].push(r);
}); });
directions.push(q);
} }
}; };
@ -58,8 +76,8 @@ export class TurtleVM extends Cat.VM<TurtleVM> {
pen = new PenState(); pen = new PenState();
pos = new Vector3(); pos = new Vector3();
q = new Quaternion(); q = new Quaternion();
prevQ = this.q;
smooth = false; smooth = false;
miter = false;
get euler(): Vector3 { get euler(): Vector3 {
return this.q.toEulerAngles(); return this.q.toEulerAngles();
@ -75,33 +93,24 @@ export class TurtleVM extends Cat.VM<TurtleVM> {
} }
forwardBy(dist: number) { forwardBy(dist: number) {
const v = new Vector3(0, 0, dist); const v = new Vector3(0, 0, dist).applyRotationQuaternionInPlace(this.q);
v.rotateByQuaternionToRef(this.q, v);
this.pos.addInPlace(v); this.pos.addInPlace(v);
if (this.pen.isDown) this.pen.push(this.pos, this.q); if (this.pen.isDown) this.pen.push(this.pos, this.q, dist === 0.0 && this.miter);
}
setQ(newQ: Quaternion) {
this.q = newQ;
}
resetQ(newQ: Quaternion) {
this.q = this.prevQ = newQ;
} }
rotate(y: number, x: number, z: number) { rotate(y: number, x: number, z: number) {
const e = this.euler; const e = this.euler;
e.addInPlaceFromFloats(x * D2R, y * D2R, z * D2R); e.addInPlaceFromFloats(x * D2R, y * D2R, z * D2R);
this.setQ(e.toQuaternion()); this.q = e.toQuaternion();
} }
relativeRotate(y: number, x: number, z: number) { relativeRotate(y: number, x: number, z: number) {
this.setQ(this.q.multiply(Quaternion.FromEulerAngles(x * D2R, y * D2R, z * D2R))); this.q = this.q.multiply(Quaternion.FromEulerAngles(x * D2R, y * D2R, z * D2R));
} }
penDown() { penDown() {
this.pen.down(); this.pen.down();
this.pen.push(this.pos, this.q); this.pen.push(this.pos, this.q, false);
} }
penUp(close: boolean) { penUp(close: boolean) {
@ -201,7 +210,7 @@ export class TurtleVM extends Cat.VM<TurtleVM> {
} }
export const TurtlePrimitives: Cat.Environment<TurtleVM> = Object.assign({}, Cat.Primitives, { export const TurtlePrimitives: Cat.Environment<TurtleVM> = Object.assign({}, Cat.Primitives, {
'Home'() { this.pos = new Vector3(); this.resetQ(new Quaternion()); return []; }, 'Home'() { this.pos = new Vector3(); this.q = new Quaternion(); return []; },
'GetPos'() { return [this.pos.asArray()]; }, 'GetPos'() { return [this.pos.asArray()]; },
'GetX'() { return [this.pos.x]; }, 'GetX'() { return [this.pos.x]; },
@ -223,7 +232,7 @@ export const TurtlePrimitives: Cat.Environment<TurtleVM> = Object.assign({}, Cat
'SetRY'(v) { this.q.y = v as number * D2R; return []; }, 'SetRY'(v) { this.q.y = v as number * D2R; return []; },
'SetRZ'(v) { this.q.z = v as number * D2R; return []; }, 'SetRZ'(v) { this.q.z = v as number * D2R; return []; },
'SetHeading'(x, y, z) { 'SetHeading'(x, y, z) {
this.resetQ(Quaternion.FromEulerAngles(x as number * D2R, y as number * D2R, z as number * D2R)); this.q = Quaternion.FromEulerAngles(x as number * D2R, y as number * D2R, z as number * D2R);
return []; return [];
}, },
@ -244,11 +253,16 @@ export const TurtlePrimitives: Cat.Environment<TurtleVM> = Object.assign({}, Cat
'ClearPen'() { this.pen.clear(); return []; }, 'ClearPen'() { this.pen.clear(); return []; },
'SetPen'() { this.pen.set(); return []; }, 'SetPen'() { this.pen.set(); return []; },
'PenScale'(sx, sy, sz) {
this.pen.templateScale = new Vector3(sx as number, sy as number, sz as number);
return [];
},
'PenDown'() { this.penDown(); return []; }, 'PenDown'() { this.penDown(); return []; },
'PenUp'() { this.penUp(false); return []; }, 'PenUp'() { this.penUp(false); return []; },
'Close'() { this.penUp(true); return []; }, 'Close'() { this.penUp(true); return []; },
'SetSmooth'(b) { this.smooth = b as boolean; return []; }, 'SetSmooth'(b) { this.smooth = b as boolean; return []; },
'SetMiter'(b) { this.miter = b as boolean; return []; },
'SetSideOrientation'(s) { 'SetSideOrientation'(s) {
switch (s) { switch (s) {
case "default": this.sideOrientation = Mesh.DEFAULTSIDE; break; case "default": this.sideOrientation = Mesh.DEFAULTSIDE; break;