Skip to content

Commit 23325a4

Browse files
committed
Merge branch 'pattern/curvature'
2 parents 29781c3 + a9d482a commit 23325a4

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Once you've completed your design, submit a Pull Request and if it works, I'll m
6363
- Circle
6464
- Cross
6565
- Cycloid ([Epicycloid](https://en.wikipedia.org/wiki/Epicycloid), [Hypocycloid](https://en.wikipedia.org/wiki/Hypocycloid), [Hypotrochoid](https://en.wikipedia.org/wiki/Hypotrochoid))
66+
- Curvature
6667
- Diameters
6768
- Free Draw
6869
- Easter Eggs ([Reference](https://math.stackexchange.com/questions/3375853/parametric-equations-for-a-true-egg-shape))

src/js/patterns/Curvature.js

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import PathHelper from '@markroland/path-helper'
2+
3+
class Curvature {
4+
5+
constructor(env) {
6+
this.key = "curvature";
7+
this.name = "Curvature";
8+
this.env = env;
9+
10+
this.config = {
11+
"radius": {
12+
"name": "Start Radius",
13+
"value": null,
14+
"input": {
15+
"type": "createSlider",
16+
"params" : [
17+
0,
18+
1,
19+
0.05,
20+
0.01
21+
],
22+
"class": "slider",
23+
"displayValue": true
24+
}
25+
},
26+
"iterations": {
27+
"name": "Iterations",
28+
"value": null,
29+
"input": {
30+
"type": "createSlider",
31+
"params" : [
32+
2,
33+
100,
34+
40,
35+
2
36+
],
37+
"class": "slider",
38+
"displayValue": true
39+
}
40+
},
41+
};
42+
43+
this.path = [];
44+
}
45+
46+
draw() {
47+
48+
const PathHelp = new PathHelper();
49+
50+
// Update object
51+
this.config.radius.value = parseFloat(document.querySelector('#pattern-controls > div:nth-child(1) > input').value);
52+
this.config.iterations.value = parseInt(document.querySelector('#pattern-controls > div:nth-child(2) > input').value);
53+
54+
// Display selected values
55+
document.querySelector('#pattern-controls > div.pattern-control:nth-child(1) > span').innerHTML = this.config.radius.value;
56+
document.querySelector('#pattern-controls > div.pattern-control:nth-child(2) > span').innerHTML = this.config.iterations.value;
57+
58+
let path = [];
59+
60+
// Set maximum radius based on table size
61+
const max_r = 0.5 * Math.min(
62+
(this.env.table.x.max - this.env.table.x.min),
63+
(this.env.table.y.max - this.env.table.y.min)
64+
);
65+
66+
// Crop Circle
67+
const cropShape = PathHelp.polygon(60, max_r);
68+
69+
// This needs to be even to mirror properly
70+
const i_max = this.config.iterations.value;
71+
72+
// const starting_radius = this.config.radius.value * max_r;
73+
const starting_radius = this.config.radius.value * max_r;
74+
const ending_radius = 40.0 * max_r;
75+
for (let i = 0; i < i_max; i++) {
76+
77+
// The radius should increase. It can be eased using different methods
78+
const radius = starting_radius + this.#easeInQuart(i/i_max) * (ending_radius - starting_radius);
79+
80+
// The y position should start out near the top and the bottom of the circle/arc
81+
// should step down by one increment of (i) as a fraction of the maximum radius,
82+
// ensuring equal spacing between each arc
83+
const y = max_r + 1.0 * radius - (max_r * (i / i_max));
84+
85+
const sides = Math.round((2 * Math.PI * radius) / (0.5 * this.env.ball.diameter));
86+
let arc = PathHelp.arc(
87+
[0, 0],
88+
radius,
89+
2 * Math.PI,
90+
0.5 * Math.PI,
91+
sides
92+
);
93+
94+
if (i % 2) {
95+
arc.reverse();
96+
}
97+
98+
arc = PathHelp.translatePath(arc, [0, y]);
99+
100+
let cropped = PathHelp.cropToShape([arc], cropShape);
101+
102+
if (cropped.length) {
103+
path = path.concat(cropped[0]);
104+
}
105+
}
106+
107+
const horizontal_line = [
108+
[-max_r, 0],
109+
[0, 0]
110+
];
111+
if (path[path.length - 1][0] > 0) {
112+
horizontal_line.reverse();
113+
}
114+
path = path.concat(horizontal_line);
115+
116+
// Duplicate and flip
117+
let flip = PathHelp.deepCopy(path);
118+
flip.reverse();
119+
flip = PathHelp.rotatePath(flip, Math.PI);
120+
flip.shift();
121+
path = path.concat(flip);
122+
123+
// Define arc from home position to start of path
124+
const arc_from_home = PathHelp.arc(
125+
[0, 0],
126+
max_r,
127+
0.5 * Math.PI,
128+
0,
129+
12
130+
);
131+
132+
// Define arc from end of path to home position
133+
const arc_to_home = PathHelp.arc(
134+
[0, 0],
135+
max_r,
136+
0.5 * Math.PI,
137+
1.5 * Math.PI,
138+
12
139+
);
140+
141+
// Redefine path with start/ending paths
142+
path = arc_from_home.concat(path, arc_to_home);
143+
144+
// path = PathHelp.simplify(path, 0.5 * this.env.ball.diameter);
145+
146+
// Simplify decimal precision
147+
path = path.map(function(point) {
148+
return point.map(function(number) {
149+
return parseFloat(number.toFixed(2));
150+
});
151+
});
152+
153+
return path;
154+
}
155+
156+
#easeOutCubic(x) {
157+
return 1 - Math.pow(1 - x, 3);
158+
}
159+
160+
#easeInQuart(x) {
161+
return x * x * x * x;
162+
}
163+
164+
#easeInCubic(x) {
165+
return x * x * x;
166+
}
167+
168+
#easeInQuad(x) {
169+
return x * x;
170+
}
171+
172+
#easeInCirc(x) {
173+
return 1 - Math.sqrt(1 - Math.pow(x, 2));
174+
}
175+
176+
#easeInExpo(x) {
177+
return x === 0 ? 0 : Math.pow(2, 10 * x - 10);
178+
}
179+
}
180+
181+
export default Curvature;

src/js/patterns/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import env from './../env.js';
33
import Coordinates from './Coordinates.js';
44
import Circle from './Circle.js';
55
import Cross from './Cross.js';
6+
import Curvature from './Curvature.js';
67
import Cycloid from './Cycloid.js';
78
import Diameters from './Diameters.js';
89
import Draw from './Draw.js';
@@ -36,6 +37,7 @@ import ZigZag from './ZigZag.js';
3637
const Patterns = {
3738
"coordinates": new Coordinates(),
3839
"circle": new Circle(env),
40+
"curvature": new Curvature(env),
3941
"cross": new Cross(env),
4042
"cycloid": new Cycloid(env),
4143
"diameters": new Diameters(env),

0 commit comments

Comments
 (0)