Skip to content

Commit 46e689b

Browse files
committed
Merge branch 'spiral-zigzag'
2 parents 0084602 + e0efd40 commit 46e689b

File tree

4 files changed

+261
-18
lines changed

4 files changed

+261
-18
lines changed

src/js/patterns/SpiralZigZag.js

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import PathHelper from '@markroland/path-helper'
2+
import * as Utilities from './utils/Utilities.js';
3+
4+
class SpiralZigZag {
5+
6+
constructor(env) {
7+
this.key = this.constructor.name.toLowerCase();
8+
this.name = this.constructor.name;
9+
this.env = env;
10+
11+
this.max_r = 0.5 * Math.min(
12+
(env.table.x.max - env.table.x.min),
13+
(env.table.y.max - env.table.y.min)
14+
);
15+
16+
this.config = {
17+
"radius": {
18+
"name": "Radius (r)",
19+
"value": null,
20+
"input": {
21+
"type": "createSlider",
22+
"params" : [
23+
1,
24+
0.5 * Math.min(env.table.x.max, env.table.y.max),
25+
0.5 * this.max_r,
26+
1
27+
],
28+
"class": "slider",
29+
"displayValue": true
30+
}
31+
},
32+
"angle": {
33+
"name": "Start Angle (𝜃)",
34+
"value": null,
35+
"input": {
36+
"type": "createSlider",
37+
"params" : [
38+
0,
39+
360,
40+
0,
41+
1
42+
],
43+
"class": "slider",
44+
"displayValue": true
45+
}
46+
},
47+
"reverse": {
48+
"name": "Reverse",
49+
"value": null,
50+
"input": {
51+
"type": "createCheckbox",
52+
"attributes" : [{
53+
"type" : "checkbox",
54+
"checked" : null
55+
}],
56+
"params": [0, 1, 0],
57+
"displayValue": false
58+
}
59+
}
60+
};
61+
62+
this.path = [];
63+
}
64+
65+
draw() {
66+
67+
// Update object
68+
this.config.radius.value = parseInt(document.querySelector('#pattern-controls > div:nth-child(1) > input').value);
69+
this.config.angle.value = parseInt(document.querySelector('#pattern-controls > div:nth-child(2) > input').value);
70+
71+
// Display selected values
72+
document.querySelector('#pattern-controls > div.pattern-control:nth-child(1) > span').innerHTML = this.config.radius.value;
73+
document.querySelector('#pattern-controls > div.pattern-control:nth-child(2) > span').innerHTML = this.config.angle.value + '°';
74+
75+
// Calculate path for Circle at center
76+
if (!this.path.length) {
77+
this.path = this.constructPath();
78+
}
79+
80+
return this.path;
81+
}
82+
83+
/**
84+
* Calculate coordinates for a circle
85+
**/
86+
constructPath() {
87+
88+
// Start path at far right
89+
let path = [
90+
];
91+
92+
const PathHelp = new PathHelper();
93+
94+
// path = PathHelp.polygon(120, this.config.radius.value);
95+
const revolutions = 9;
96+
let spiral = Utilities.spiral(
97+
this.max_r - this.env.ball.diameter,
98+
this.max_r - revolutions * 2 * this.env.ball.diameter,
99+
revolutions,
100+
120
101+
);
102+
103+
path = Utilities.zigZag(spiral, this.env.ball.diameter);
104+
105+
path.shift();
106+
107+
path = [[this.max_r, 0]].concat(path);
108+
109+
// path = spiral;
110+
111+
// path = path.concat(
112+
// // console.log(
113+
// Utilities.arcBetweenPoints(
114+
// path[path.length - 1][0],
115+
// path[path.length - 1][1],
116+
// 0,
117+
// 0.5 * this.env.table.y.max,
118+
// this.env.ball.diameter
119+
// )
120+
// )
121+
122+
123+
// ---
124+
125+
path = PathHelp.reflectPath(path, "y");
126+
127+
return path;
128+
}
129+
}
130+
131+
export default SpiralZigZag;

src/js/patterns/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import Rhodonea from './Rhodonea.js';
2626
import ShapeMorph from './ShapeMorph.js';
2727
import ShapeSpin from './ShapeSpin.js';
2828
import Spiral from './Spiral.js';
29+
import SpiralZigZag from './SpiralZigZag.js';
2930
import Spokes from './Spokes.js';
3031
import Star from './Star.js';
3132
import Superellipse from './Superellipse.js';
@@ -59,6 +60,7 @@ const Patterns = {
5960
"shapemorph": new ShapeMorph(env),
6061
"shapespin": new ShapeSpin(),
6162
"spiral": new Spiral(env),
63+
"spiralzigzag": new SpiralZigZag(env),
6264
"sunset": new Sunset(env),
6365
"logspiral": new LogarithmicSpiral(env),
6466
"spokes": new Spokes(env),

src/js/patterns/utils/Utilities.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import PathHelper from '@markroland/path-helper'
2+
3+
export function spiral(r1, r2, n, sides) {
4+
5+
let path = [];
6+
7+
const PathHelp = new PathHelper();
8+
9+
const stepSize = (2 * Math.PI * r1) / sides; // Approximate step size based on initial radius
10+
let theta = 0;
11+
let r = r1;
12+
13+
while (r >= r2) {
14+
path.push([
15+
r * Math.cos(theta),
16+
r * Math.sin(theta),
17+
]);
18+
19+
theta += stepSize / r; // Increment angle based on step size
20+
r = r1 + (theta / (2 * Math.PI * n)) * (r2 - r1); // Increment radius proportionally
21+
}
22+
23+
// path = PathHelp.simplify(path, stepSize);
24+
25+
// const theta1 = 0;
26+
// const theta2 = n * 2 * Math.PI;
27+
// const i_max = n * sides;
28+
// for (let i = 0; i <= i_max; i++) {
29+
// const r = r1 + (i/i_max) * (r2 - r1);
30+
// const theta = theta1 + (i/i_max) * (theta2 - theta1);
31+
32+
// path.push([
33+
// r * Math.cos(theta),
34+
// r * Math.sin(theta),
35+
// ]);
36+
// }
37+
38+
// path = PathHelp.simplify(path, step_size);
39+
40+
return path;
41+
}
42+
43+
export function zigZag(path, offset) {
44+
45+
const PathHelp = new PathHelper();
46+
47+
let innerPath = PathHelp.offsetPath(path, -offset);
48+
49+
// Need this for closed shapes:
50+
// innerPath = PathHelp.shiftPath(innerPath, 2);
51+
// innerPath.push(innerPath[0]);
52+
// innerPath.splice(1, 1);
53+
54+
let outerPath = PathHelp.offsetPath(path, offset);
55+
56+
// Need this for closed shapes:
57+
// outerPath = PathHelp.shiftPath(outerPath, 2);
58+
// outerPath.push(outerPath[0]);
59+
// outerPath.splice(1, 1);
60+
61+
// ZigZag
62+
let newPath = [];
63+
for (let i = 0; i < path.length; i++) {
64+
if (i % 2 === 0) {
65+
newPath.push(innerPath[i]);
66+
newPath.push(outerPath[i]);
67+
} else {
68+
newPath.push(outerPath[i]);
69+
newPath.push(innerPath[i]);
70+
}
71+
}
72+
path = newPath;
73+
74+
return newPath;
75+
}
76+
77+
/**
78+
* This may not do quite what I want it to do.
79+
*/
80+
export function arcBetweenPoints(x1, y1, x2, y2, step_size) {
81+
82+
const PathHelp = new PathHelper();
83+
84+
let path = [[x1, y1]];
85+
86+
const r1 = Math.sqrt(x1 * x1 + y1 * y1);
87+
const theta1 = Math.atan2(y1, x1);
88+
89+
const r2 = Math.sqrt(x2 * x2 + y2 * y2);
90+
const theta2 = Math.atan2(y2, x2);
91+
92+
const i_max = 1000;
93+
for (let i = 0; i < i_max; i++) {
94+
95+
const r = r1 + (i/i_max) * (r2 - r1);
96+
const theta = theta1 + (i/i_max) * (theta2 - theta1);
97+
98+
path.push([
99+
r * Math.cos(theta),
100+
r * Math.sin(theta),
101+
]);
102+
}
103+
104+
path = PathHelp.simplify(path, step_size);
105+
106+
return path;
107+
}

vite.config.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
import { defineConfig } from 'vite';
22
import { resolve } from 'path';
33

4-
export default defineConfig({
5-
base: '/sand-table-pattern-maker/',
6-
root: 'src',
7-
publicDir: '../public',
8-
build: {
9-
outDir: '../dist',
10-
emptyOutDir: true,
11-
rollupOptions: {
12-
input: {
13-
main: resolve(__dirname, 'src/index.html'),
14-
env: resolve(__dirname, 'src/js/env.js'),
4+
export default defineConfig(({ mode }) => {
5+
const isLocalhost = mode === 'development';
6+
return {
7+
base: isLocalhost ? '/' : '/sand-table-pattern-maker/',
8+
root: 'src',
9+
publicDir: '../public',
10+
build: {
11+
outDir: '../dist',
12+
emptyOutDir: true,
13+
rollupOptions: {
14+
input: {
15+
main: resolve(__dirname, 'src/index.html'),
16+
env: resolve(__dirname, 'src/js/env.js'),
17+
},
1518
},
1619
},
17-
},
18-
server: {
19-
open: true,
20-
},
21-
optimizeDeps: {
22-
include: ['@markroland/path-helper'],
23-
},
20+
server: {
21+
open: true,
22+
},
23+
optimizeDeps: {
24+
include: ['@markroland/path-helper'],
25+
},
26+
};
2427
});

0 commit comments

Comments
 (0)