All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.Pie.kt Maven / Gradle / Ivy

The newest version!
package com.juul.krayon.shape

import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

private const val TAU = (2 * PI).toFloat()

public fun pie(): Pie = Pie(value = { it })

public class Pie internal constructor(
    private val value: (T) -> Float,
    startAngle: Float = 0f,
    endAngle: Float = TAU,
    padAngle: Float = 0f,
) {

    /** Overall start angle (start angle of the first arc). In radians, where `0` is at 12 o'clock and positive increases move clockwise. */
    public var startAngle: Float = startAngle
        private set

    /** Overall end angle (end angle of the last arc). In radians, where `0` is at 12 o'clock and positive increases move clockwise. */
    public var endAngle: Float = endAngle
        private set

    /** Angular separation between arcs in radians. */
    public var padAngle: Float = padAngle
        private set

    /** Returns a new [Pie] which can compute a numeric value for complex data types. */
    public fun  value(value: (T2) -> Float): Pie = Pie(value, startAngle, endAngle, padAngle)

    public fun startAngle(value: Float): Pie = apply { startAngle = value }

    public fun endAngle(value: Float): Pie = apply { endAngle = value }

    public fun padAngle(value: Float): Pie = apply { padAngle = value }

    public operator fun invoke(vararg data: T): List> = this(data.toList())

    public operator fun invoke(data: List): List> {
        if (data.isEmpty()) return emptyList()

        val da = min(TAU, max(-TAU, endAngle - startAngle))
        val p = min(abs(da) / data.size, padAngle)
        val pa = p * (if (da < 0) -1 else 1)

        val values = data.map(value)
        check(values.all { it >= 0 }) {
            val index = values.indexOfFirst { it < 0 }
            "Values must be greater than or equal to zero, but got `${values[index]}` for item `${data[index]}`."
        }
        check(values.any { it > 0f }) { "At least one value must be greater than zero, but were all zero for items `$data`." }
        val sum = values.sum()

        var angle = startAngle
        val k = (da - data.size * pa) / sum
        return values.mapIndexed { index, value ->
            val endAngle = angle + (value * k) + pa
            Slice(
                data = data[index],
                value = value,
                index = index,
                startAngle = angle,
                endAngle = endAngle,
                padAngle = p,
            ).also {
                angle = endAngle
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy