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

io.data2viz.voronoi.Edge.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2018-2019. data2viz sàrl.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package io.data2viz.voronoi

import io.data2viz.geom.Point


internal var wEdges = mutableListOf()

fun createBorderEdge(left:Site, v0: Point, v1: Point?): Edge {
    val ret = Edge (left)
    ret.start = v0
    ret.end = v1
    return ret
}


/**
 * left: the site on the left side of the edge
 * right: the site on the right side of the edge; null for a clipped border edge
 */
class Edge(
        var left: Site,
        var right: Site? =  null) {

    var start: Point? = null
    var end: Point? = null

    companion object {

        fun createEdge(left: Site, right: Site, v0: Point? = null, v1: Point? = null): Edge {
            val edge = Edge(left, right)
            wEdges.add(edge)
            val index = wEdges.size -1

            wCells!![left.index]!!.halfedges.add(index)
            wCells!![right.index]!!.halfedges.add(index)
            if (v0 != null) setEdgeEnd(edge, left, right, v0)
            if (v1 != null) setEdgeEnd(edge, right, left, v1)
            return edge
        }

        fun setEdgeEnd(edge: Edge, left: Site, right: Site, vertex: Point) {
            if (edge.start == null && edge.end == null) {
                edge.start = vertex
                edge.left = left
                edge.right = right
            } else if (edge.left === right) {
                edge.end = vertex
            } else {
                edge.start = vertex
            }
        }

    }

    fun clip(clipStart: Point, clipEnd: Point):Boolean {
        val a = start
        val b = end
        val ax = a!!.x
        val ay = a.y
        val bx = b!!.x
        val by = b.y

        var t0 = 0.0
        var t1 = 1.0
        val dx = bx - ax
        val dy = by - ay
        var r = clipStart.x - ax

        if(dx == 0.0 && r > 0.0) return false
        r /=  dx
        if (dx < 0) {
            if (r < t0) return false
            if (r < t1) t1 = r
        } else if (dx > 0) {
            if (r > t1) return false
            if (r > t0) t0 = r
        }

        r = clipEnd.x - ax
        if (dx == 0.0 && r < 0) return false
        r /= dx
        if (dx < 0) {
            if (r > t1) return false
            if (r > t0) t0 = r
        } else if (dx > 0) {
            if (r < t0) return false
            if (r < t1) t1 = r
        }

        r = clipStart.y - ay
        if (dy == 0.0 && r > 0) return false
        r /= dy
        if (dy < 0) {
            if (r < t0) return false
            if (r < t1) t1 = r
        } else if (dy > 0) {
            if (r > t1) return false
            if (r > t0) t0 = r
        }

        r = clipEnd.y - ay
        if (dy == 0.0 && r < 0) return false
        r /= dy
        if (dy < 0) {
            if (r > t1) return false
            if (r > t0) t0 = r
        } else if (dy > 0) {
            if (r < t0) return false
            if (r < t1) t1 = r
        }

        if (t0 <= 0.0 && t1 >= 1.0) return true // TODO Better check?

        if (t0 > 0) start = Point(ax + t0 * dx, ay + t0 * dy)
        if (t1 < 1) end = Point(ax + t1 * dx, ay + t1 * dy)
        return true
    }


    fun connect(clipStart: Point, clipEnd: Point):Boolean {
        var v1 = end
        if (v1 != null) return true

        val x0 = clipStart.x
        val y0 = clipStart.y
        val x1 = clipEnd.x
        val y1 = clipEnd.y

        var v0 = start
        val lx = left.x
        val ly = left.y
        val rx = right!!.x
        val ry = right!!.y
        val fx = (lx + rx) / 2
        val fy = (ly + ry) / 2

        val fm:Double
        val fb:Double

        if (ry == ly) {
            if (fx < x0 || fx >= x1) return false
            if (lx > rx) {
                if (v0 == null) v0 = Point(fx, y0)
                else if (v0.y >= y1) return false
                v1 = Point(fx, y1)
            } else {
                if (v0 == null) v0 = Point(fx, y1)
                else if (v0.y < y0) return false
                v1 = Point(fx, y0)
            }
        } else {
            fm = (lx - rx) / (ry - ly)
            fb = fy - fm * fx
            if (fm < -1 || fm > 1) {
                if (lx > rx) {
                    if (v0 == null) v0 = Point((y0 - fb) / fm, y0)
                    else if (v0.y >= y1) return false
                    v1 = Point((y1 - fb) / fm, y1)
                } else {
                    if (v0 == null) v0 = Point((y1 - fb) / fm, y1)
                    else if (v0.y < y0) return false
                    v1 = Point((y0 - fb) / fm, y0)
                }
            } else {
                if (ly < ry) {
                    if (v0 == null) v0 = Point(x0, fm * x0 + fb)
                    else if (v0.x >= x1) return false
                    v1 = Point(x1, fm * x1 + fb)
                } else {
                    if (v0 == null) v0 = Point(x1, fm * x1 + fb)
                    else if (v0.x < x0) return false
                    v1 = Point(x0, fm * x0 + fb)
                }
            }
        }

        start = v0
        end = v1
        return true
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy