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

it.unibo.alchemist.model.implementations.properties.PhysicalPedestrian2D.kt Maven / Gradle / Ivy

There is a newer version: 36.0.11
Show newest version
/*
 * Copyright (C) 2010-2022, 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.model.implementations.properties

import it.unibo.alchemist.model.implementations.positions.Euclidean2DPosition
import it.unibo.alchemist.model.interfaces.Node
import it.unibo.alchemist.model.interfaces.Node.Companion.asProperty
import it.unibo.alchemist.model.interfaces.Node.Companion.asPropertyOrNull
import it.unibo.alchemist.model.interfaces.environments.Physics2DEnvironment
import it.unibo.alchemist.model.interfaces.environments.PhysicsEnvironment
import it.unibo.alchemist.model.interfaces.geometry.euclidean2d.Euclidean2DShape
import it.unibo.alchemist.model.interfaces.geometry.euclidean2d.Euclidean2DShapeFactory
import it.unibo.alchemist.model.interfaces.geometry.euclidean2d.Euclidean2DTransformation
import it.unibo.alchemist.model.interfaces.properties.AreaProperty
import it.unibo.alchemist.model.interfaces.properties.CognitiveProperty
import it.unibo.alchemist.model.interfaces.properties.PhysicalPedestrian2D
import it.unibo.alchemist.model.util.RandomGeneratorExtension.nextDouble
import org.apache.commons.math3.random.RandomGenerator

/**
 * Base implementation of a pedestrian's capability to experience physical interactions in a 2D space.
 */
class PhysicalPedestrian2D(
    private val randomGenerator: RandomGenerator,
    /**
     * The environment in which the node is moving.
     */
    val environment: Physics2DEnvironment,
    override val node: Node,
) : PhysicalPedestrian2D {

    private val nodeShape by lazy { node.asProperty>().shape }

    private val desiredSpaceTreshold: Double = randomGenerator.nextDouble(minimumSpaceTreshold, maximumSpaceThreshold)

    override val comfortRay: Double get() {
        val cognitiveModel = node.asPropertyOrNull>()?.cognitiveModel
        return if (cognitiveModel?.wantsToEscape() == true) {
            desiredSpaceTreshold / 3
        } else {
            desiredSpaceTreshold
        }
    }

    override val comfortArea: Euclidean2DShape get() = environment
        .shapeFactory
        .circle(node.asProperty>().shape.radius + comfortRay)
        .transformed { origin(environment.getPosition(node)) }

    override fun repulsionForce(other: Node): Euclidean2DPosition {
        val myShape = nodeShape.transformed { origin(environment.getPosition(node)) }
        val otherShape = environment.getShape(other)
        return (myShape.centroid - otherShape.centroid).let {
            val desiredDistance = myShape.radius + comfortRay + otherShape.radius
            /*
             * it is the vector leading from the center of other to the center of this node, it.magnitude is the
             * actual distance between the two nodes.
             */
            it.normalized() * (desiredDistance - it.magnitude).coerceAtLeast(0.0) / it.magnitude
        }
    }

    override fun physicalForces(
        environment: PhysicsEnvironment,
    ) = environment.getNodesWithin(comfortArea)
        .asSequence()
        .minusElement(node)
        .filter { it.asPropertyOrNull>() != null }
        .map { repulsionForce(it) }
        /*
         * Discard infinitesimal forces.
         */
        .filter { it.magnitude > Double.MIN_VALUE }
        .toList()

    override fun cloneOnNewNode(node: Node) = PhysicalPedestrian2D(randomGenerator, environment, node)

    companion object {
        /**
         * Minimum value for normal state [comfortRay].
         */
        private const val minimumSpaceTreshold = 0.1
        /**
         * Maximum value for normal state [comfortRay].
         */
        private const val maximumSpaceThreshold = 1.0
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy