Collections
Loops in other languages are often used to construct or manipulate collections.
In Kotlin we have many instructions that facilitate working with collections and make loops unnecessary.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.scatter
import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.primitives.regularPolygon
import org.openrndr.shape.Circle
import org.openrndr.shape.Segment2D
fun main() = application {
program {
val c = List(20) {
Circle(drawer.bounds.center, 1.0 + it * it)
}
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
drawer.circles(c)
}
}
}
Here an example of randomly dropping elements from a list.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.scatter
import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.primitives.regularPolygon
import org.openrndr.shape.Circle
import org.openrndr.shape.Segment2D
fun main() = application {
program {
val c = List(200) {
Circle(drawer.bounds.center, 1.0 + it * 2)
}.filter {
Random.bool(0.25)
}
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
drawer.circles(c)
}
}
}
Mapping
With mapping we can convert a list into a different list with the same number of elements.
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.scatter
import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.primitives.regularPolygon
import org.openrndr.shape.Circle
import org.openrndr.shape.Segment2D
val numbers = List(10) {
it
}
val words = numbers.map {
"hello"
}
val largerNumbers = numbers.map {
it * 3
}
println(largerNumbers)
Next lets use mapping for something much more meaningful: we will obtain a list of random points, and we will map those points to pentagons.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.scatter
import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.primitives.regularPolygon
import org.openrndr.shape.Circle
import org.openrndr.shape.Segment2D
fun main() = application {
program {
val points = drawer.bounds.scatter(40.0, distanceToEdge = 50.0)
val pentagons = points.map {
regularPolygon(5, it, 30.0, Double.uniform(0.0, 360.0))
}
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
drawer.contours(pentagons)
}
}
}
Flatten
Sometimes we will map each item in a list to a new list, which will give us a list of lists. Methods like drawer.contours only can take a one-dimensional list as an argument, therefore in those case we should apply the flatten() operation to the list.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.scatter
import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.primitives.regularPolygon
import org.openrndr.shape.Circle
import org.openrndr.shape.Segment2D
fun main() = application {
program {
val base = List(10) {
Circle(drawer.bounds.center, Double.uniform(50.0, 350.0)).contour
}
val hairs = base.map { circle ->
List(200) {
val t = it / 200.0
val point = circle.position(t)
val normal = circle.normal(t)
Segment2D(point, point + normal * 30.0).contour
}
}.flatten().filter {
Random.bool(0.5)
}
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
drawer.contours(base)
drawer.contours(hairs)
}
}
}