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

it.unibo.alchemist.model.cognitive.actions.CognitiveAgentFollowScalarField.kt Maven / Gradle / Ivy

There is a newer version: 35.0.0
Show newest version
/*
 * 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.model.cognitive.actions

import it.unibo.alchemist.model.Environment
import it.unibo.alchemist.model.EnvironmentWithObstacles
import it.unibo.alchemist.model.Node
import it.unibo.alchemist.model.Position2D
import it.unibo.alchemist.model.Reaction
import it.unibo.alchemist.model.cognitive.PedestrianProperty
import it.unibo.alchemist.model.geometry.Transformation
import it.unibo.alchemist.model.geometry.Vector2D
import it.unibo.alchemist.model.physics.PhysicsEnvironment

/**
 * Moves the node where the given scalar field is higher.
 */
class CognitiveAgentFollowScalarField(
    environment: Environment,
    reaction: Reaction,
    override val pedestrian: PedestrianProperty,
    /**
     * The position of either maximum or minimum value of the scalar field, can be null if such a position doesn't
     * exist or isn't known. Its use is explained in [nextPosition].
     */
    private val center: P? = null,
    /**
     * A function mapping each position to a scalar value (= the scalar field).
     */
    private val valueIn: (P) -> Double,
) : AbstractSteeringAction(environment, reaction, pedestrian)
    where P : Position2D

, P : Vector2D

, A : Transformation

{ /** * @returns the next relative position reached by the node. The set of reachable positions is discretized * using [Vector2D.surrounding] from the current position (radius is [maxWalk]). If the scalar field has a * [center], two more positions are taken into account: one towards the center along the direction connecting the * latter to the current position, and another away from the center along the same direction. The position with * maximum value is then selected: if its value is higher than the current one, the node moves there. * Otherwise, it doesn't move at all. */ override fun nextPosition(): P = currentPosition.let { currentPosition -> val centerProjectedPositions = center?.let { val direction = (center - currentPosition).coerceAtMost(maxWalk) listOf(currentPosition + direction, currentPosition - direction) } (currentPosition.surrounding(maxWalk) + centerProjectedPositions.orEmpty()) .asSequence() .enforceObstacles(currentPosition) .enforceOthers() /* * Next relative position. */ .maxOr(currentPosition) - currentPosition } override fun cloneAction(node: Node, reaction: Reaction): CognitiveAgentFollowScalarField = CognitiveAgentFollowScalarField(environment, reaction, node.pedestrianProperty, center, valueIn) private fun Sequence

.enforceObstacles(currentPosition: P): Sequence

= when (environment) { is EnvironmentWithObstacles<*, T, P> -> map { (environment as EnvironmentWithObstacles<*, T, P>).next(currentPosition, it) } else -> this } private fun Sequence

.enforceOthers(): Sequence

= when (environment) { is PhysicsEnvironment -> map { (environment as PhysicsEnvironment).farthestPositionReachable(node, it) } else -> this } private fun Sequence

.maxOr(position: P): P = maxByOrNull { valueIn(it) } ?.takeIf { valueIn(it) > valueIn(position) } ?: position }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy