Skip to content

Commit

Permalink
fix: make sure gallery specimens not warning; update specimens
Browse files Browse the repository at this point in the history
  • Loading branch information
katestange committed Oct 24, 2024
1 parent 5c8b48e commit fd853e8
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 27 deletions.
9 changes: 9 additions & 0 deletions doc/code-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,15 @@ And that's all there is to it. With this spec file newly in place,
`npm run test:unit` reports three more passed tests than before. It's ready to
be committed and made part of a pull request.

### Updating an existing end-to-end test

If you modify an existing visualizer with an existing end-to-end test, you may
find yourself in the situation of having to update the end-to-end snapshots
(screenshots) to reflect the new expected behavior. To do so, you can run the
command `npm run test:e2e -- --update-snapshots`. This will produce new
expected snapshots in the directory /e2e/tests, which you will need to add as
part of your commit.

### Adding an end-to-end test

The Playwright framework for end-to-end testing is broadly similar. In this
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified e2e/tests/featured.spec.ts-snapshots/ThueTrellis-chromium-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 8 additions & 5 deletions src/shared/defineFeatured.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const featuredSIMs = [
'Thue Trellis',
'Turtle',
'OEIS A010060',
'domain=0+1&turns=15+-165&steps=2+3&speed=5'
'domain=0+1&turns=15+-165&steps=2+3&speed=10'
+ '&folds=0+0&stretches=0+0'
+ '&pathLook=false&bgColor=e0def7&strokeColor=5e8d85'
),
specimenQuery(
Expand Down Expand Up @@ -50,6 +51,7 @@ const featuredSIMs = [
'Turtle',
'Formula',
'&domain=-1+1&turns=30+120&steps=30+30&strokeWeight=2'
+ '&folds=0+0&stretches=0+0'
+ '&bgColor=5d509f&strokeColor=7a9f6f',
'formula=sign%28sin%28n%2B1%29%29'
),
Expand All @@ -64,17 +66,18 @@ const featuredSIMs = [
'Turtle',
'OEIS A000045',
'&domain=0+1+2+3+4+5+6+7+8&turns=8+120+0+0+0+0+0+0+0'
+ '&steps=20+200+0+0+0+0+0+0+0&foldControls=true'
+ '&folds=200+0+0+0+0+0+0+0+0+&speed=100&bgColor=4f4875'
+ '&steps=40+400+0+0+0+0+0+0+0&foldControls=true'
+ '&folds=200+0+0+0+0+0+0+0+0&stretches=0+0+0+0+0+0+0+0+0'
+ '&speed=100&bgColor=4f4875'
+ '&strokeColor=cec0c0',
'&modulus=9&last=999&length=1000'
),
specimenQuery(
'Beatty DNA',
'Turtle',
'OEIS A001951',
'&domain=0+1+2&turns=79+0+45&steps=5+2+6&foldControls=true&folds=0+0+0'
+ '&speed=10&bgColor=e9eee3&strokeColor=4b7a81',
'&domain=0+1+2&turns=79+0+45&steps=2.5+1.5+3&folds=0+0+0'
+ '&speed=10&bgColor=6c162b&strokeColor=be9b9b',
'&modulus=3'
),
]
Expand Down
72 changes: 50 additions & 22 deletions src/visualizers/Turtle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ some sequences, like A014577 "The regular paper-folding sequence", naturally
have a small domain.)
**/
domain: {
default: [0n, 1n, 2n, 3n, 4n] as bigint[],
default: [0n, 1n, 2n] as bigint[],
type: ParamType.BIGINT_ARRAY,
displayName: 'Domain',
required: true,
Expand All @@ -68,7 +68,7 @@ element of the domain will be interpreted as an instruction to turn
x degrees, where x is the first number in this field.
**/
turns: {
default: [30, 45, 60, 90, 120] as number[],
default: [30, 45, 60] as number[],
type: ParamType.NUMBER_ARRAY,
displayName: 'Turning angles',
required: true,
Expand All @@ -84,7 +84,7 @@ elements as the domain. As with turn angles, the n-th step length
will be interpreted as the step length for the n-th domain element.
**/
steps: {
default: [20, 20, 20, 20, 20] as number[],
default: [20, 20, 20] as number[],
type: ParamType.NUMBER_ARRAY,
displayName: 'Step lengths',
required: true,
Expand All @@ -103,23 +103,49 @@ will be interpreted as the step length for the n-th domain element.
required: false,
},
/** md
- foldRate: When this is non-zero, the path will animate.
This is the angle increment added to the turning
angles each frame. The units are (1/10^5)-th of a degree.
For example, if the entry is a `2`, then in each
frame of the animation, the turn angle for
the every domain element will increase by (2/10^5)-th
of a degree. The result
looks a little like protein folding.
**/
foldRate: {
default: 0,
type: ParamType.NUMBER,
displayName: 'Uniform folding rate',
required: false,
description:
'turns on animation: rate of increase of'
+ ' turn angles; '
+ 'units of 1/10^5 degree per frame',
hideDescription: false,
visibleDependency: 'animationControls',
visibleValue: true,
},
/** md
- folding: a list of numbers. When these are non-zero, the path will animate.
These are angle increments added to the turning
angles each frame. They correspond
positionally to the domain elements. Must contain the same number of elements
as the domain. The units are (1/10^5)-th of a degree.
For example, if the first
entry here is a `2`, then in each frame of the animation, the turn angle for
the first domain element will increase by (2/10^5)-th of a degree. The result
the first domain element will increase by (2/10^5)-th of a degree.
If foldRate is set, the effect is cumulative.
The result
looks a little like protein folding.
**/
folds: {
default: [0, 0, 0, 0, 0] as number[],
default: [0, 0, 0] as number[],
type: ParamType.NUMBER_ARRAY,
displayName: 'Folding rates',
displayName: 'Individual folding rates',
required: false,
description:
'turns on animation: list of angle increments per frame in units'
'turns on animation: list'
+ ' of angle increments per frame in units'
+ ' of 1/10^5 degree, in order corresponding'
+ ' to the sequence values listed in domain',
hideDescription: false,
Expand All @@ -133,9 +159,9 @@ each frame. They correspond positionally to the domain elements.
Must contain the same number of elements as the domain.
**/
stretches: {
default: [0, 0, 0, 0, 0] as number[],
default: [0, 0, 0] as number[],
type: ParamType.NUMBER_ARRAY,
displayName: 'Stretching rates',
displayName: 'Individual stretching rates',
required: false,
description:
'turns on animation: list of step length increments'
Expand All @@ -151,7 +177,7 @@ Must contain the same number of elements as the domain.
pathLook: {
default: true,
type: ParamType.BOOLEAN,
displayName: 'Path start/speed/styling ↴',
displayName: 'Path speed/styling ↴',
required: false,
},
/**
Expand Down Expand Up @@ -243,7 +269,7 @@ class Turtle extends P5GLVisualizer(paramDesc) {
// variables holding the parameter values
// these don't change except in setup()
private firstIndex = 0n // first term
private folding = false // whether there's any folding
private animating = false // whether there's any fold/stretch
private growth = 0 // growth of path per frame
private maxLength = -1 // longest we will allow path to get

Expand Down Expand Up @@ -405,20 +431,22 @@ class Turtle extends P5GLVisualizer(paramDesc) {

// create a map from sequence values to turn increments
// notice if path is static or we are folding
this.folding = false
this.animating = false
for (let i = 0; i < this.domain.length; i++) {
if (this.foldsInternal[i] != 0) this.folding = true
// cumulative effect of two ways to turn on folding
const thisFold = this.foldsInternal[i] + this.foldRate
if (thisFold != 0) this.animating = true
this.foldMap.set(
this.domain[i].toString(),
(Math.PI / 180) * (this.foldsInternal[i] / this.foldDenom)
(Math.PI / 180) * (thisFold / this.foldDenom)
)
}

// create a map from sequence values to stretch increments
// notice if path is static or we are animating
// rename folding to animating?
for (let i = 0; i < this.domain.length; i++) {
if (this.stretchesInternal[i] != 0) this.folding = true
if (this.stretchesInternal[i] != 0) this.animating = true
this.stretchMap.set(
this.domain[i].toString(),
this.stretchesInternal[i] / this.stretchDenom
Expand All @@ -434,15 +462,15 @@ class Turtle extends P5GLVisualizer(paramDesc) {

// reset variables
this.firstIndex = this.seq.first
this.maxLength = this.folding
this.maxLength = this.animating
? this.throttleLimit
: Number.MAX_SAFE_INTEGER
if (this.seq.length < this.maxLength) {
this.maxLength = Number(this.seq.length)
}
this.growth = this.speed
// draw the entire path every frame if folding
if (this.folding) this.growth = this.maxLength
if (this.animating) this.growth = this.maxLength

this.refresh()
}
Expand Down Expand Up @@ -482,7 +510,7 @@ class Turtle extends P5GLVisualizer(paramDesc) {
draw() {
if (this.handleDrags()) this.cursor = 0
const sketch = this.sketch
if (this.folding) this.refresh()
if (this.animating) this.refresh()
else if (this.cursor === 0) this.redraw()

// compute more of path as needed:
Expand Down Expand Up @@ -511,7 +539,7 @@ class Turtle extends P5GLVisualizer(paramDesc) {

// See if we can create a new chunk:
const fullChunks = Math.floor(this.cursor / CHUNK_SIZE)
if (!this.folding && fullChunks > this.chunks.length) {
if (!this.animating && fullChunks > this.chunks.length) {
// @ts-expect-error The @types/p5 package omitted this function
sketch.beginGeometry()
sketch.beginShape()
Expand All @@ -526,7 +554,7 @@ class Turtle extends P5GLVisualizer(paramDesc) {

// stop drawing if no animation
if (
!this.folding
!this.animating
&& !sketch.mouseIsPressed
&& this.vertices.length > this.maxLength
&& !this.pathFailure
Expand All @@ -542,15 +570,15 @@ class Turtle extends P5GLVisualizer(paramDesc) {
extendPath(currentFrames: number, targetLength: number) {
// First compute the rotMap and stepMap to use:
let rotMap = this.rotMap
if (this.folding) {
if (this.animating) {
rotMap = new Map<string, number>()
for (const [entry, rot] of this.rotMap) {
const extra = currentFrames * (this.foldMap.get(entry) ?? 0)
rotMap.set(entry, rot + extra)
}
}
let stepMap = this.stepMap
if (this.folding) {
if (this.animating) {
stepMap = new Map<string, number>()
for (const [entry, step] of this.stepMap) {
const extra =
Expand Down

0 comments on commit fd853e8

Please sign in to comment.