Visualize segment-pair concavity/convexity

apps.simpleTests.ConvexConcave-2022-12-29-12.05.39

I hope the code says it all :slight_smile:

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.math.Polar
import org.openrndr.shape.ShapeContour

/**
 * Visualize segment left-turns and right-turns on a ShapeContour.
 */
fun main() = application {
    program {
        val pointCount = 16

        // Create a ShapeContour out of points positioned using polar coordinates
        // around the center of the screen.
        val c = ShapeContour.fromPoints(
            List(pointCount) {
                val angle = it * 360.0 / pointCount
                val radius = listOf(150.0, 200.0).random()
                Polar(angle, radius).cartesian + drawer.bounds.center
            }, closed = true
        )

        // Create a list of segments to work with. If the shape is closed, we need to add the first segment
        // to the end of the list to be able to calculate the angle between the last segment and
        // the first one
        val segs = if(c.closed) c.segments + c.segments.first() else c.segments

        // For each pair of segments, compare the normal at the end of the first segment with
        // the direction at the start of the second segment. The dot product will be either positive
        // or negative, telling us if it's convex or concave
        val segData : List<Pair<Segment, Boolean>> = 
            segs.zipWithNext().map { (segA, segB) -> 
                segA to (segA.normal(1.0).dot(segB.direction(0.0)) > 0.0)
        }
        extend {
            drawer.clear(ColorRGBa.WHITE)

            drawer.fill = ColorRGBa.WHITE.shade(0.9)
            drawer.contour(c)

            // Visualize left-turns and right-turns in two different colors
            segData.forEach { (seg, positive) ->
                drawer.fill = if(positive) ColorRGBa.MAGENTA else ColorRGBa.CYAN
                drawer.circle(seg.end, 10.0)
            }
        }
    }
}
1 Like