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

io.data2viz.geo.path.PathCentroid.kt Maven / Gradle / Ivy

There is a newer version: 0.8.0-RC5
Show newest version
package io.data2viz.geo.path

import io.data2viz.geo.projection.Stream
import kotlin.math.sqrt

class PathCentroid : Stream {
    private var _X0 = 0.0
    private var _Y0 = 0.0
    private var _Z0 = 0.0
    private var _X1 = 0.0
    private var _Y1 = 0.0
    private var _Z1 = 0.0
    private var _X2 = 0.0
    private var _Y2 = 0.0
    private var _Z2 = 0.0
    private var x00 = Double.NaN
    private var y00 = Double.NaN
    private var x0 = Double.NaN
    private var y0 = Double.NaN

    private var currentPoint: (Double, Double) -> Unit = ::centroidPoint
    private var currentLineStart: () -> Unit = ::centroidLineStart
    private var currentLineEnd: () -> Unit = ::centroidLineEnd

    internal fun result(): DoubleArray {
        val centroid = when {
            _Z2 != .0 -> doubleArrayOf(_X2 / _Z2, _Y2 / _Z2)
            _Z1 != .0 -> doubleArrayOf(_X1 / _Z1, _Y1 / _Z1)
            _Z0 != .0 -> doubleArrayOf(_X0 / _Z0, _Y0 / _Z0)
            else -> doubleArrayOf(Double.NaN, Double.NaN)
        }

        _X0 = 0.0
        _Y0 = 0.0
        _Z0 = 0.0
        _X1 = 0.0
        _Y1 = 0.0
        _Z1 = 0.0
        _X2 = 0.0
        _Y2 = 0.0
        _Z2 = 0.0

        return centroid
    }

    override fun point(x: Double, y: Double, z: Double) = currentPoint(x, y)
    override fun lineStart() = currentLineStart()
    override fun lineEnd() = currentLineEnd()
    override fun polygonStart() {
        currentLineStart = ::centroidRingStart
        currentLineEnd = ::centroidRingEnd
    }

    override fun polygonEnd() {
        currentPoint = ::centroidPoint
        currentLineStart = ::centroidLineStart
        currentLineEnd = ::centroidLineEnd
    }

    private fun centroidPoint(x: Double, y: Double) {
        _X0 += x
        _Y0 += y
        ++_Z0
    }

    private fun centroidLineStart() {
        currentPoint = ::centroidPointFirstLine
    }

    private fun centroidPointFirstLine(x: Double, y: Double) {
        currentPoint = ::centroidPointLine
        x0 = x
        y0 = y
        centroidPoint(x, y)
    }

    private fun centroidPointLine(x: Double, y: Double) {
        val dx = x - x0
        val dy = y - y0
        val dz = sqrt(dx * dx + dy * dy)
        _X1 += dz * (x0 + x) / 2.0
        _Y1 += dz * (y0 + y) / 2.0
        _Z1 += dz
        x0 = x
        y0 = y
        centroidPoint(x, y)
    }

    private fun centroidLineEnd() {
        currentPoint = ::centroidPoint
    }

    private fun centroidRingStart() {
        currentPoint = ::centroidPointFirstRing
    }

    private fun centroidRingEnd() = centroidPointRing(x00, y00)

    private fun centroidPointFirstRing(x: Double, y: Double) {
        currentPoint = ::centroidPointRing
        x00 = x
        y00 = y
        x0 = x
        y0 = y
        centroidPoint(x, y)
    }

    private fun centroidPointRing(x: Double, y: Double) {
        val dx = x - x0
        val dy = y - y0
        var dz = sqrt((dx * dx) + (dy * dy))

        _X1 += dz * (x0 + x) / 2.0
        _Y1 += dz * (y0 + y) / 2.0
        _Z1 += dz

        dz = y0 * x - x0 * y
        _X2 += dz * (x0 + x)
        _Y2 += dz * (y0 + y)
        _Z2 += dz * 3
        x0 = x
        y0 = y
        centroidPoint(x, y)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy