use futures::future::FutureExt;
use geo::{Area, Centroid};
use crate::definitions::agent as definitions_agent;
use crate::definitions::tst as definitions_tst;
use crate::definitions::tst::SpeedCompute;
use crate::execution::tst as execution_tst;
use crate::execution::tst::AgentExecutorTrait;
use crate::{Error, Result};
mod utils;
#[derive(Default, Clone)]
pub struct SimulationResult
{
estimated_cost: f32,
final_states: crate::states::States,
}
impl SimulationResult
{
pub fn get_estimated_cost(&self) -> f32
{
self.estimated_cost
}
}
pub async fn simulate_execution(
initial_states: crate::states::States,
capabilities: definitions_agent::capabilities::Capabilities,
tst_node: definitions_tst::Node,
) -> Result<SimulationResult>
{
let agent = Agent {
capabilities: capabilities,
..Default::default()
};
agent.simulation_result.lock().unwrap().final_states = initial_states;
let executor =
execution_tst::DefaultAgentExecutor::<MoveToExecutor, SearchAreaExecutor>::from_agent(&agent);
let r = executor.execute(tst_node);
let res = r.await;
if let Err(e) = res
{
Err(e.into())
}
else
{
Ok(agent.simulation_result.lock().unwrap().clone())
}
}
#[derive(Clone, Default)]
struct Agent
{
capabilities: definitions_agent::capabilities::Capabilities,
simulation_result: std::sync::Arc<std::sync::Mutex<SimulationResult>>,
}
impl execution_tst::Agent for Agent {}
struct MoveToExecutor
{
agent: Agent,
}
impl execution_tst::CreatableFromAgent<Agent, MoveToExecutor> for MoveToExecutor
{
fn from_agent(agent: &Agent) -> MoveToExecutor
{
MoveToExecutor {
agent: agent.clone(),
}
}
}
impl execution_tst::Executor<definitions_tst::MoveTo> for MoveToExecutor
{
fn execute<'a, 'b>(
&'a self,
_executors: &'b impl execution_tst::Executors,
t: definitions_tst::MoveTo,
) -> execution_tst::ExecutionResult<'b>
{
let simulation_result = self.agent.simulation_result.clone();
let capabilities = self.agent.capabilities.clone();
async move {
let mut simulation_result = simulation_result.lock().unwrap();
let current_position = simulation_result.final_states.get_position()?;
let move_to_capability = capabilities
.get_move()
.map_err(|e| crate::Error::ExecutionFailed(e.to_string()))?;
let vel = t
.params
.speed
.compute_velocity(move_to_capability.get_max_velocity());
simulation_result.estimated_cost += utils::distance(
current_position.x,
t.params.waypoint.longitude,
current_position.y,
t.params.waypoint.latitude,
);
simulation_result
.final_states
.update_state(crate::states::Position {
x: t.params.waypoint.longitude,
y: t.params.waypoint.latitude,
})?;
Ok::<(), Error>(())
}
.boxed()
}
}
struct SearchAreaExecutor
{
agent: Agent,
}
impl execution_tst::CreatableFromAgent<Agent, SearchAreaExecutor> for SearchAreaExecutor
{
fn from_agent(agent: &Agent) -> SearchAreaExecutor
{
SearchAreaExecutor {
agent: agent.clone(),
}
}
}
impl execution_tst::Executor<definitions_tst::SearchArea> for SearchAreaExecutor
{
fn execute<'a, 'b>(
&'a self,
_executors: &'b impl execution_tst::Executors,
t: definitions_tst::SearchArea,
) -> execution_tst::ExecutionResult<'b>
{
let simulation_result = self.agent.simulation_result.clone();
async move {
let mut simulation_result = simulation_result.lock().unwrap();
let current_position = simulation_result.final_states.get_position()?;
let mut polygon_points = Vec::<(f32, f32)>::new();
for pt in t.params.area
{
polygon_points.push((pt.longitude, pt.latitude));
}
polygon_points.push(polygon_points[0]);
let polygon = geo::Polygon::new(geo::LineString::from(polygon_points), vec![]);
let center = polygon.centroid().unwrap();
simulation_result.estimated_cost += utils::distance(
current_position.x,
center.x(),
current_position.y,
center.y(),
);
simulation_result.estimated_cost += polygon.unsigned_area();
simulation_result
.final_states
.update_state(crate::states::Position {
x: center.x(),
y: center.y(),
})?;
Ok::<(), Error>(())
}
.boxed()
}
}