Creative Coding Challenge: Tangents: the code

tangents.kt
tangents.kt
1    import ddf.minim.Minim
2    import ddf.minim.analysis.FFT
3    import org.openrndr.Fullscreen
4    import org.openrndr.Program
5    import org.openrndr.UnfocusBehaviour
6    import org.openrndr.animatable.Animatable
7    import org.openrndr.animatable.easing.Easing
8    import org.openrndr.application
9    import org.openrndr.color.ColorRGBa
10   import org.openrndr.draw.LineCap
11   import org.openrndr.math.IntVector2
12   import org.openrndr.extensions.Screenshots
13   import org.openrndr.extra.gui.GUI
14   import org.openrndr.extra.olive.Olive
15   import org.openrndr.extra.parameters.*
16   import org.openrndr.extra.shadestyles.linearGradient
17   import org.openrndr.extra.shadestyles.radialGradient
18   import org.openrndr.ffmpeg.ScreenRecorder
19   import org.openrndr.math.Polar
20   import org.openrndr.math.Vector2
21   import org.openrndr.math.asDegrees
22   import org.openrndr.panel.ControlManager
23   import org.openrndr.panel.layout
24   import org.openrndr.panel.style.*
25   import org.openrndr.shape.shape
26   import java.io.File
27   import java.io.FileInputStream
28   import java.io.InputStream
29   import java.lang.Math.random
30   import kotlin.math.acos
31   import kotlin.math.pow
32   import kotlin.math.sqrt
33   
34   fun main() = application {
35   
36       // The setup
37       configure {
38           width = 768
39           height = 768
40           position = IntVector2(400, 200)
41           fullscreen = Fullscreen.DISABLED
42           windowResizable = true
43           title = "OpenRNDR Tutorial"
44           unfocusBehaviour = UnfocusBehaviour.THROTTLE    // behaviour when program window is unfocused. NORMAL keeps it running at full speed
45   
46       }
47   
48       // The draw, executed once
49       program {
50           val R = width / 3.0
51           val nLines = 100
52   
53           val animation = object : Animatable() {
54               var r = 475.89
55           }
56   
57           //
58           //      GUI
59           //
60   
61           val gui = GUI()
62           val settings = object {
63               @DoubleParameter("Chord Length", 0.0, 770.0)
64               var refR: Double = 400.0
65   
66               @DoubleParameter("Stroke Weight", 0.1, 5.0)
67               var strokeWeight: Double = 0.5
68   
69               @DoubleParameter("Animation Duration", 0.0, 10000.0)
70               var animationDuration: Double = 1000.0
71   
72               @DoubleParameter("Animation Amplitude", 0.0, 50.0)
73               var animationAmplitude: Double = 1.0
74   
75               @BooleanParameter("Animate")
76               var animate = false
77   
78               @BooleanParameter("Curves")
79               var curves = false
80   
81               @BooleanParameter("Relative curve control")
82               var rcc = false
83   
84               @XYParameter("Curve control", -400.0, 400.0, -400.0, 400.0, showVector = true, invertY = false)
85               var controlPoint = Vector2(0.0, 0.0)
86   
87               @DoubleParameter("Curve control weighting", 0.0, 1.0)
88               var controlWeight = 0.5
89           }
90   
91           val colors = object {
92               @ColorParameter("Background color 1", order = 0)
93               var bgcol1 = randomColor()
94   
95               @ColorParameter("Background color 2", order = 1)
96               var bgcol2 = randomColor()
97   
98               @ColorParameter("Circle color 1", order = 3)
99               var circlecol1 = randomColor()
100  
101              @ColorParameter("Circle color 2", order = 4)
102              var circlecol2 = randomColor()
103  
104              @ColorParameter("Chords color", order = 5)
105              var chordcol = randomColor()
106  
107              @ActionParameter("Randomize Colors", order = 6)
108              fun randomizeColors() {
109                  bgcol1 = randomColor()
110                  bgcol2 = randomColor()
111                  circlecol1 = randomColor()
112                  circlecol1 = randomColor()
113                  chordcol = randomColor()
114              }
115          }
116  
117          gui.compartmentsCollapsedByDefault = false
118          gui.add(settings, "Settings")
119          gui.add(colors, "Colors")
120          extend(gui)
121  
122  
123          // Extensions. With optional { options setup }
124          extend(Screenshots()) {
125  //            scale =  4.0
126          }
127          extend(ScreenRecorder()) {}
128  
129          //
130          //      AUDIO
131          //
132  /* 
133   
134          val minim = Minim(object : Object() { 
135              fun sketchPath(fileName: String): String { 
136                  return fileName 
137              } 
138              fun createInput(fileName: String): InputStream { 
139                  return FileInputStream(File(fileName)) 
140              } 
141          }) 
142          val lineIn = minim.lineIn 
143          val fft = FFT(lineIn.bufferSize(), lineIn.sampleRate()) 
144  */
145  
146  
147          // The actual drawing loop
148          extend {
149  
150  
151  
152              //Background
153  //            drawer.shadeStyle = radialGradient(SketchColors.eggplant, SketchColors.seaGreen, length = 0.5)
154              drawer.shadeStyle = radialGradient(colors.bgcol1, colors.bgcol2, length = 0.5)
155              drawer.rectangle(0.0, 0.0, width.toDouble(), height.toDouble())
156  
157              if (settings.animate)
158                  animation.updateAnimation()
159  
160              if (!animation.hasAnimations()) {
161                  animation.apply {
162                      ::r.animate(sqrt(settings.animationAmplitude), settings.animationDuration.toLong(), Easing.CubicInOut)
163                      ::r.complete()
164                      ::r.animate(-sqrt(settings.animationAmplitude), settings.animationDuration.toLong(), Easing.CubicInOut)
165                      ::r.complete()
166                  }
167              }
168  
169              drawer.stroke = null
170  
171              drawer.translate(width / 2.0, height / 2.0)
172  
173              drawer.shadeStyle = radialGradient(colors.circlecol1, colors.circlecol2, length = 0.5)
174  //            drawer.fill = SketchColors.eggplant
175              drawer.circle(0.0, 0.0, R)
176  
177              val startPoint = Vector2(R, 0.0)
178              val chordTheta: Double = if (settings.animate)
179                  triangulate(R, R, animation.r/10 + settings.refR)
180              else
181                  triangulate(R, R, settings.refR)
182  
183              var theta = 0.0
184              var previousPoint: Vector2
185              var nextPoint = Vector2.ZERO
186  
187              if (!chordTheta.isNaN() && chordTheta != 0.0) {
188  
189  
190                  val s = shape {
191                      val c = contour {
192                          moveTo(startPoint)
193  
194                          for (i in 0..nLines) {
195                              theta += chordTheta
196                              previousPoint = nextPoint
197                              nextPoint = Vector2.fromPolar(Polar(theta.asDegrees, R))
198  
199                              if (settings.curves) {
200                                  if (settings.rcc) {
201                                      val p = settings.controlWeight
202                                      curveTo((nextPoint.times(p) - previousPoint.times(1.0 - p)) / 2.0, nextPoint)
203                                  } else {
204                                      curveTo(settings.controlPoint, nextPoint)
205                                  }
206                              } else
207                                  lineTo(nextPoint)
208                          }
209  
210  //                    close()
211                      }
212  
213                  }
214  //                drawer.fill = SketchColors.lightSalmon
215                  drawer.stroke = colors.chordcol
216  //                drawer.shadeStyle = linearGradient(ColorRGBa.BLUE, ColorRGBa.RED, rotation = -90.0)
217                  drawer.strokeWeight = settings.strokeWeight
218                  drawer.lineCap = LineCap.BUTT
219  //            drawer.contour(c)
220                  drawer.shape(s)
221  //            drawer.contour(s.outline)
222  
223              }
224          }
225  
226  
227  
228          //
229          //      UI
230          //
231  
232  
233      }
234  }
235  
236  fun triangulate(a: Double, b: Double, c: Double):Double {
237      // Returns an angle in radians
238      // a and b are adjacent sides
239      // c is the opposite side to the desired angle
240      return -acos((a.pow(2.0) + b.pow(2.0) - c.pow(2.0))/(2 * a * b))
241  }
242  
243  
244  class SketchColors {
245      companion object {
246          val seaGreen = ColorRGBa.fromHex(0x13efb4)
247          val mintGreen = ColorRGBa.fromHex(0x98FF98)
248          val eggplant = ColorRGBa.fromHex(0x60495A)
249          val lightSalmon = ColorRGBa.fromHex(0xFF9B71)
250      }
251  }
252  
253  fun randomColor(): ColorRGBa {
254      return ColorRGBa(random(), random(), random())
255  }

Leave a comment

Your email address will not be published. Required fields are marked *