it.unibo.alchemist.model.actions.FollowAtDistance.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alchemist-euclidean-geometry Show documentation
Show all versions of alchemist-euclidean-geometry Show documentation
Alchemist geometric components for Euclidean spaces
/*
* 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.actions
import it.unibo.alchemist.model.Context
import it.unibo.alchemist.model.Environment
import it.unibo.alchemist.model.Molecule
import it.unibo.alchemist.model.Node
import it.unibo.alchemist.model.Reaction
import it.unibo.alchemist.model.movestrategies.speed.GloballyConstantSpeed
import it.unibo.alchemist.model.positions.Euclidean2DPosition
import it.unibo.alchemist.util.Anys.toPosition
import kotlin.math.cos
import kotlin.math.min
import kotlin.math.sin
/**
* Makes the [Node] follow a [target] defined in a [Molecule] with some [speed],
* but keeping a [distance] from it.
*
* @param concentration type
* @param environment the environment containing the nodes
* @param node the follower
* @param reaction the reaction hosting this action
* @param target molecule from which to read the destination to follow in the form of coordinates or a tuple
* @param distance the distance to keep from the destination
* @param speed the maximum speed
*/
class FollowAtDistance(
node: Node,
private val reaction: Reaction,
private val environment: Environment,
private val target: Molecule,
private val distance: Double,
private val speed: Double,
) : AbstractAction(node) {
private val speedStrategy = GloballyConstantSpeed(reaction, speed)
override fun cloneAction(node: Node, reaction: Reaction) =
FollowAtDistance(
node,
reaction,
environment,
target,
distance,
speed,
)
override fun execute() {
node.getConcentration(target)?.also {
val targetPosition = it.toPosition(environment)
val currentPosition = environment.getPosition(node)
var destination = targetPosition.surroundingPointAt(currentPosition - targetPosition, distance)
if (currentPosition != destination) { // avoid "bouncing"
val currentSpeed = min(
speedStrategy.getNodeMovementLength(destination),
currentPosition.distanceTo(destination),
)
val direction = destination - currentPosition
val angle = direction.asAngle
destination = currentPosition +
Euclidean2DPosition(currentSpeed * cos(angle), currentSpeed * sin(angle))
environment.moveNodeToPosition(node, destination)
}
}
}
override fun getContext() = Context.LOCAL
}