Last active
April 2, 2021 01:29
-
-
Save ylegall/a636601e75539e4ad0c9d7ac705601c0 to your computer and use it in GitHub Desktop.
Revisions
-
ylegall revised this gist
Feb 3, 2021 . 1 changed file with 4 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -49,6 +49,7 @@ fun main() = application { /** * create a circle packing by iteratively relaxing circles * NOTE this requires a custom KD Tree implementation. */ fun relaxPoints( points: MutableList<Vector2>, @@ -110,6 +111,7 @@ fun main() = application { val newPoints = initialPoints.toMutableList() // change the max iterations here for time/accuracy trade-off repeat(6) { // move the points closer to the center @@ -126,6 +128,8 @@ fun main() = application { //val avg = integralImage. map(0.0, 256.0, 36.0, 6.0, result.toDouble() / (radius * radius)) } // change the max iterations here for time/accuracy trade-off relaxPoints(newPoints, radii, 30) } println("done computing points for $filename") @@ -136,7 +140,6 @@ fun main() = application { val points2 = getImagePoints("data/images/image-2.jpg") val points3 = getImagePoints("data/images/image-3.jpg") extend(ScreenRecorder()) { outputFile = "stipple.mp4" frameClock = true -
ylegall revised this gist
Feb 2, 2021 . 1 changed file with 0 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -110,14 +110,6 @@ fun main() = application { val newPoints = initialPoints.toMutableList() repeat(6) { // move the points closer to the center -
ylegall created this gist
Feb 2, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,174 @@ import org.openrndr.application import org.openrndr.color.ColorRGBa import org.openrndr.draw.ColorFormat import org.openrndr.draw.colorBuffer import org.openrndr.draw.loadImage import org.openrndr.draw.shadeStyle import org.openrndr.extra.noise.poissonDiskSampling import org.openrndr.extra.olive.oliveProgram import org.openrndr.extras.easing.easeQuadIn import org.openrndr.extras.easing.easeQuadInOut import org.openrndr.ffmpeg.MP4Profile import org.openrndr.ffmpeg.ScreenRecorder import org.openrndr.math.Vector2 import org.openrndr.math.map import org.openrndr.math.mix import org.openrndr.math.smoothstep import org.openrndr.shape.IntRectangle import org.openrndr.shape.Rectangle import studio.rndnr.packture.IntegralImage import kotlin.math.abs /** * This is a template for a live program. * * It uses oliveProgram {} instead of program {}. All code inside the * oliveProgram {} can be changed while the program is running. */ fun main() = application { configure { width = 920 height = 920 } //oliveProgram { program { val radius = 12 val initialPoints = poissonDiskSampling(width.toDouble(), height.toDouble(), radius.toDouble()).also { println(it.size) } val totalFrames = 420 fun cubicPulse(center: Double, width: Double, x: Double): Double { val x1 = abs(x - center) if (x1 > width) return 0.0 val x2 = x1 / width return 1.0 - x2 * x2 * (3.0 - 2.0 * x2) } /** * create a circle packing by iteratively relaxing circles */ fun relaxPoints( points: MutableList<Vector2>, radii: List<Double>, maxIterations: Int = -1, minOverlap: Double = 0.001 ): Int { var iterations = 0 val positionDeltas = MutableList(points.size) { Vector2.ZERO } val maxRadius = radii.maxOrNull() ?: 16.0 while (iterations < maxIterations || maxIterations < 0) { val index = KDTree2.fromPoints(points.indices.toList()) { points[it] } var changed = false for (i in points.indices) { val p1 = points[i] val radius1 = radii[i] val neighbors = index.queryRange(Rectangle.fromCenter(p1, 4 * maxRadius, 4 * maxRadius)).filter { it != i } var overlappingNeighbors = 0 for (j in neighbors) { val p2 = points[j] val radius2 = radii[j] val delta = p1 - p2 val dist = delta.length val overlap = radius1 + radius2 - dist if (overlap > minOverlap) { overlappingNeighbors++ positionDeltas[i] += delta.normalized * (overlap / 2) } } if (overlappingNeighbors > 0) { changed = true positionDeltas[i] = positionDeltas[i] / overlappingNeighbors.toDouble() } } if (!changed) { break } for (i in points.indices) { points[i] += positionDeltas[i] } positionDeltas.fill(Vector2.ZERO) iterations++ } println("total iterations: $iterations") return iterations } fun getImagePoints(filename: String): List<Vector2> { val image = loadImage(filename) image.shadow.download() val integralImage = IntegralImage.fromColorBufferShadow(image.shadow) val newPoints = initialPoints.toMutableList() extend(ScreenRecorder()) { frameRate = 30 frameClock = true profile = MP4Profile().apply { mode(MP4Profile.WriterMode.Lossless) } outputFile = "stipple.mp4" maximumFrames = totalFrames.toLong() } repeat(6) { // move the points closer to the center for (i in newPoints.indices) { val delta = newPoints[i] - image.bounds.center newPoints[i] += delta.normalized * 4.0 //newPoints[i] = mix(newPoints[i], image.bounds.center, 0.05) } val radii: List<Double> = newPoints.map { point -> val x = point.x - radius/2 val y = point.y - radius/2 val result = integralImage.sum(IntRectangle(x.toInt(), y.toInt(), radius, radius)) //val avg = integralImage. map(0.0, 256.0, 36.0, 6.0, result.toDouble() / (radius * radius)) } relaxPoints(newPoints, radii, 30) } println("done computing points for $filename") return newPoints } val points1 = getImagePoints("data/images/image-1.jpg") val points2 = getImagePoints("data/images/image-2.jpg") val points3 = getImagePoints("data/images/image-3.jpg") extend(ScreenRecorder()) { outputFile = "stipple.mp4" frameClock = true frameRate = 30 profile = MP4Profile().apply { mode(MP4Profile.WriterMode.Lossless) } maximumFrames = totalFrames.toLong() } extend { val t = ((frameCount - 1) % totalFrames) / totalFrames.toDouble() val imagePoints = when { t <= 0.33 -> points1 t <= 0.66 -> points2 else -> points3 } val t1 = (t * 3.0) % 1.0 val factor = smoothstep(0.0, 0.75, cubicPulse(0.5, 0.45, t1)) val framePoints = initialPoints.indices.map { i -> mix(initialPoints[i], imagePoints[i], factor * factor) } drawer.stroke = null drawer.fill = ColorRGBa.WHITE drawer.circles(framePoints, 4.0) } } }