[orx-shapes] Add gradient to BezierPatch
This commit is contained in:
42
orx-shapes/src/demo/kotlin/DemoBezierPatch04.kt
Normal file
42
orx-shapes/src/demo/kotlin/DemoBezierPatch04.kt
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extensions.Screenshots
|
||||||
|
import org.openrndr.extensions.SingleScreenshot
|
||||||
|
import org.openrndr.extra.shapes.bezierPatch
|
||||||
|
import org.openrndr.shape.Circle
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 800
|
||||||
|
height = 800
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
if (System.getProperty("takeScreenshot") == "true") {
|
||||||
|
extend(SingleScreenshot()) {
|
||||||
|
this.outputFile = System.getProperty("screenshotPath")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extend {
|
||||||
|
drawer.clear(ColorRGBa.PINK)
|
||||||
|
val bp = bezierPatch(Circle(width / 2.0, height / 2.0, 350.0).contour)
|
||||||
|
|
||||||
|
for (i in 0..50) {
|
||||||
|
drawer.stroke = ColorRGBa.BLACK.opacify(1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j in 1 until 50 step 2) {
|
||||||
|
for (i in 1 until 50 step 2) {
|
||||||
|
val p = bp.position(i / 50.0, j / 50.0)
|
||||||
|
val g2 = bp.gradient(i / 50.0, j / 50.0).normalized
|
||||||
|
val g = g2.perpendicular()
|
||||||
|
drawer.lineSegment(p, p + g2 * 10.0)
|
||||||
|
drawer.lineSegment(p, p - g2 * 10.0)
|
||||||
|
drawer.lineSegment(p, p + g * 10.0)
|
||||||
|
drawer.lineSegment(p, p - g * 10.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.openrndr.extra.shapes
|
package org.openrndr.extra.shapes
|
||||||
|
|
||||||
|
import org.openrndr.math.Matrix44
|
||||||
import org.openrndr.math.Vector2
|
import org.openrndr.math.Vector2
|
||||||
import org.openrndr.shape.Rectangle
|
import org.openrndr.shape.Rectangle
|
||||||
import org.openrndr.shape.Segment
|
import org.openrndr.shape.Segment
|
||||||
@@ -24,7 +25,18 @@ class BezierPatch(val points: List<List<Vector2>>) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun coeffs(t: Double): DoubleArray {
|
fun transform(transform: Matrix44) = BezierPatch(points.map { r ->
|
||||||
|
r.map { (transform * it.xy01).div.xy }
|
||||||
|
})
|
||||||
|
|
||||||
|
private fun coeffs2(t: Double): DoubleArray {
|
||||||
|
val it = 1.0 - t
|
||||||
|
val it2 = it * it
|
||||||
|
val t2 = t * t
|
||||||
|
return doubleArrayOf(it2, 2 * it * t, t2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun coeffs3(t: Double): DoubleArray {
|
||||||
val it = 1.0 - t
|
val it = 1.0 - t
|
||||||
val it2 = it * it
|
val it2 = it * it
|
||||||
val it3 = it2 * it
|
val it3 = it2 * it
|
||||||
@@ -39,8 +51,8 @@ class BezierPatch(val points: List<List<Vector2>>) {
|
|||||||
* @param v a value between 0 and 1
|
* @param v a value between 0 and 1
|
||||||
*/
|
*/
|
||||||
fun position(u: Double, v: Double): Vector2 {
|
fun position(u: Double, v: Double): Vector2 {
|
||||||
val csu = coeffs(u)
|
val csu = coeffs3(u)
|
||||||
val csv = coeffs(v)
|
val csv = coeffs3(v)
|
||||||
var result = Vector2.ZERO
|
var result = Vector2.ZERO
|
||||||
for (j in 0 until 4) {
|
for (j in 0 until 4) {
|
||||||
for (i in 0 until 4) {
|
for (i in 0 until 4) {
|
||||||
@@ -50,6 +62,37 @@ class BezierPatch(val points: List<List<Vector2>>) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a gradient vector on the patch by using its u,v parameterization
|
||||||
|
* @param u a value between 0 and 1
|
||||||
|
* @param v a value between 0 and 1
|
||||||
|
*/
|
||||||
|
fun gradient(u: Double, v: Double): Vector2 {
|
||||||
|
val f0 = List(4) { MutableList(3) { Vector2.ZERO } }
|
||||||
|
for (j in 0 until 4) {
|
||||||
|
for (i in 0 until 3) {
|
||||||
|
f0[j][i] = points[j][i+1] - points[j][i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val f1 = List(3) { MutableList(3) { Vector2.ZERO } }
|
||||||
|
for (j in 0 until 3) {
|
||||||
|
for (i in 0 until 3) {
|
||||||
|
f1[j][i] = f0[j+1][i] - f0[j][i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val csu = coeffs2(u)
|
||||||
|
val csv = coeffs2(v)
|
||||||
|
var result = Vector2.ZERO
|
||||||
|
for (j in 0 until 3) {
|
||||||
|
for (i in 0 until 3) {
|
||||||
|
result += f1[j][i] * csu[i] * csv[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a random point on the path
|
* Generate a random point on the path
|
||||||
* @return a point that is uniformly distributed in uv space
|
* @return a point that is uniformly distributed in uv space
|
||||||
@@ -57,7 +100,7 @@ class BezierPatch(val points: List<List<Vector2>>) {
|
|||||||
fun randomPoint(random: Random = Random.Default) = position(random.nextDouble(), random.nextDouble())
|
fun randomPoint(random: Random = Random.Default) = position(random.nextDouble(), random.nextDouble())
|
||||||
|
|
||||||
fun horizontal(v: Double): ShapeContour {
|
fun horizontal(v: Double): ShapeContour {
|
||||||
val cs = coeffs(v)
|
val cs = coeffs3(v)
|
||||||
val cps = Array(4) { Vector2.ZERO }
|
val cps = Array(4) { Vector2.ZERO }
|
||||||
for (j in 0 until 4) {
|
for (j in 0 until 4) {
|
||||||
for (i in 0 until 4) {
|
for (i in 0 until 4) {
|
||||||
@@ -68,7 +111,7 @@ class BezierPatch(val points: List<List<Vector2>>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun vertical(u: Double): ShapeContour {
|
fun vertical(u: Double): ShapeContour {
|
||||||
val cs = coeffs(u)
|
val cs = coeffs3(u)
|
||||||
val cps = Array(4) { Vector2.ZERO }
|
val cps = Array(4) { Vector2.ZERO }
|
||||||
for (j in 0 until 4) {
|
for (j in 0 until 4) {
|
||||||
for (i in 0 until 4) {
|
for (i in 0 until 4) {
|
||||||
@@ -139,7 +182,7 @@ fun bezierPatch(shapeContour: ShapeContour, alpha: Double = 1.0 / 3.0): BezierPa
|
|||||||
listOf(c3.control[1], x00, x01, c1.control[0]),
|
listOf(c3.control[1], x00, x01, c1.control[0]),
|
||||||
listOf(c3.control[0], x10, x11, c1.control[1]),
|
listOf(c3.control[0], x10, x11, c1.control[1]),
|
||||||
listOf(c2.end, c2.control[1], c2.control[0], c2.start),
|
listOf(c2.end, c2.control[1], c2.control[0], c2.start),
|
||||||
)
|
)
|
||||||
return BezierPatch(cps)
|
return BezierPatch(cps)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +200,7 @@ fun bezierPatch(corners: List<Vector2>, alpha: Double = 1.0 / 3.0): BezierPatch
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Distort a shape contour
|
* Distort a shape contour
|
||||||
*/
|
*/
|
||||||
fun BezierPatch.distort(shapeContour: ShapeContour, referenceRectangle: Rectangle = shapeContour.bounds): ShapeContour {
|
fun BezierPatch.distort(shapeContour: ShapeContour, referenceRectangle: Rectangle = shapeContour.bounds): ShapeContour {
|
||||||
val distortedSegments = shapeContour.segments.map {
|
val distortedSegments = shapeContour.segments.map {
|
||||||
val c = it.cubic
|
val c = it.cubic
|
||||||
|
|||||||
Reference in New Issue
Block a user