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

commonMain.it.unibo.alchemist.boundary.webui.common.renderer.BitmapRenderer.kt Maven / Gradle / Ivy

/*
 * Copyright (C) 2010-2023, Danilo Pianini and contributors
 * listed, for each module, in the respective subproject's build.gradle.kts file.
 *
 * This file is part of Alchemist, and is distributed under the terms of the
 * GNU General Public License, with a linking exception,
 * as described in the file LICENSE in the Alchemist distribution's top directory.
 */

package it.unibo.alchemist.boundary.webui.common.renderer

import it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate
import it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate
import it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate
import korlibs.image.bitmap.Bitmap
import korlibs.image.bitmap.Bitmap32
import korlibs.image.bitmap.context2d
import korlibs.image.color.Colors
import korlibs.image.vector.Context2d
import korlibs.math.geom.Point

/**
 * This implementation renders a [Bitmap].
 * The rendering works on 2D environments only as it uses a [Context2d].
 * @param  the type of the concentration surrogate.
 */
class BitmapRenderer : Renderer {

    private companion object {
        private const val defaultNodeRadius = 0.1f
        private const val defaultHeight = 1000
        private const val defaultWidth = 1000
        private const val defaultScaleFactor = 25
    }

    /**
     * Renders the environment.
     * @param environmentSurrogate the
     * [it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate] to render.
     * @return a [Bitmap] representing the environment.
     */
    override fun render(environmentSurrogate: EnvironmentSurrogate): Bitmap {
        require(environmentSurrogate.dimensions == 2)
        return Bitmap32(defaultWidth, defaultHeight, premultiplied = false).context2d {
            cartesianPlane()
            translate(width / 2.0, height / 2.0)
            scale(defaultScaleFactor, defaultScaleFactor)
            environmentSurrogate.nodes.forEach {
                alchemistNode(it, defaultNodeRadius)
            }
        }
    }

    /**
     * Draws the two cartesian axis on the [Context2d].
     */
    private fun Context2d.cartesianPlane() {
        fill(Colors.WHITE)
        beginPath()
        moveTo((width / 2).toDouble(), 0.0)
        lineTo((width / 2).toDouble(), height.toDouble())
        moveTo(0.0, (height / 2).toDouble())
        lineTo(width.toDouble(), (height / 2).toDouble())
        stroke()
    }

    /**
     * Draws a [it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate]
     * on the [Context2d].
     *
     * @param node the node surrogate to draw.
     * @param radius the radius of the node.
     */
    private fun Context2d.alchemistNode(node: NodeSurrogate, radius: Float) {
        beginPath()
        circle(node.position.toPoint(), radius)
        stroke()
    }

    private fun PositionSurrogate.toPoint(): Point {
        require(dimensions == 2)
        return Point(coordinates[0], coordinates[1])
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy