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

it.unibo.alchemist.model.cognitive.navigation.GoalOrientedExploration.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.navigation

import it.unibo.alchemist.model.cognitive.NavigationStrategy
import it.unibo.alchemist.model.cognitive.actions.NavigationAction2D
import it.unibo.alchemist.model.geometry.ConvexPolygon
import it.unibo.alchemist.model.geometry.Euclidean2DConvexShape
import it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage
import it.unibo.alchemist.model.positions.Euclidean2DPosition

/**
 * A [NavigationStrategy] allowing to explore the environment looking for something specific whose position
 * is unknown.
 * The client can specify a list of [unknownDestinations]: these can be recognized once they're in sight,
 * but the node doesn't know their position until that moment (think e.g. of exits in an evacuation
 * scenario). More specifically, unknown destinations can be detected if located in a room adjacent to the
 * room the node is into. Once a destination is detected, the node will reach it and stop.
 *
 * @param T the concentration type.
 * @param L the type of landmarks of the node's cognitive map.
 * @param R the type of edges of the node's cognitive map, representing the [R]elations between landmarks.
 */
open class GoalOrientedExploration(
    action: NavigationAction2D,
    private val unknownDestinations: List,
) : Explore(action) {

    override fun inNewRoom(newRoom: ConvexPolygon) =
        reachUnknownDestination(newRoom, orElse = { super.inNewRoom(newRoom) })

    /**
     * If one or more unknown destinations are inside [newRoom] (= the room the node is into), the closest
     * one is approached. Otherwise, if one or more destinations are in a room adjacent to the current one, the
     * related doors are weighted using [weightExit] and the one with minimum weight is crossed. [orElse] is
     * executed otherwise.
     */
    protected open fun reachUnknownDestination(newRoom: ConvexPolygon, orElse: () -> Unit) = with(action) {
        unknownDestinations
            .filter { newRoom.contains(it) }
            .minByOrNull { it.distanceTo(pedestrianPosition) }
            ?.let { moveToFinal(it) }
            ?: doorsInSight()
                .filter { it.leadsToUnknownDestination() }
                .minByOrNull { weightExit(it) }
                ?.let { crossDoor(it) }
            ?: orElse()
    }

    protected open fun Euclidean2DPassage.leadsToUnknownDestination(): Boolean =
        unknownDestinations.any { head.contains(it) }

    /**
     * Assigns a weight to a door (= passage) leading to an unknown destination (e.g. an exit).
     * By default, the exit's distance and its congestion are considered.
     */
    protected open fun weightExit(door: Euclidean2DPassage): Double = with(door) {
        distanceToPedestrian() * congestionFactor(head)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy