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 ;
0 commit comments