use crate::copp::CoppObjective as RustCoppObjective;
use crate::ffi::c::core::status::clear_last_error;
use crate::ffi::c::robot::CoppTorqueForC;
use crate::ffi::c::{CoppRobot, CoppSliceF64, CoppStatus, CoppVecF64};
use crate::solver::copp3_socp::{
Copp3Problem as RustCopp3Problem, Copp3ProblemBuilder as RustCopp3ProblemBuilder,
};
use crate::solver::topp3_socp::{
Topp3Problem as RustTopp3Problem, Topp3ProblemBuilder as RustTopp3ProblemBuilder,
};
use std::slice;
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CoppObjectiveKind {
Time = 0,
Linear = 1,
ThermalEnergy = 2,
TotalVariationTorque = 3,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct CoppObjective {
pub kind: CoppObjectiveKind,
pub weight: f64,
pub alpha: CoppSliceF64,
pub beta: CoppSliceF64,
pub normalize: CoppSliceF64,
}
impl CoppObjective {
pub(crate) unsafe fn as_rust_objective<'a>(
&self,
allow_total_variation_torque: bool,
) -> Result<RustCoppObjective<'a>, CoppStatus> {
match self.kind {
CoppObjectiveKind::Time => Ok(RustCoppObjective::Time(self.weight)),
CoppObjectiveKind::Linear => {
let alpha = unsafe { self.alpha.as_slice()? };
let beta = unsafe { self.beta.as_slice()? };
Ok(RustCoppObjective::Linear(self.weight, alpha, beta))
}
CoppObjectiveKind::ThermalEnergy => {
let normalize = unsafe { self.normalize.as_slice()? };
Ok(RustCoppObjective::ThermalEnergy(self.weight, normalize))
}
CoppObjectiveKind::TotalVariationTorque => {
if !allow_total_variation_torque {
return Err(CoppStatus::InvalidArgument);
}
let normalize = unsafe { self.normalize.as_slice()? };
Ok(RustCoppObjective::TotalVariationTorque(
self.weight,
normalize,
))
}
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Copp2Problem {
pub robot: *const CoppRobot,
pub idx_s_start: usize,
pub idx_s_final: usize,
pub a_start: f64,
pub a_final: f64,
pub objectives: *const CoppObjective,
pub num_objectives: usize,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Topp2Problem {
pub robot: *const CoppRobot,
pub idx_s_start: usize,
pub idx_s_final: usize,
pub a_start: f64,
pub a_final: f64,
}
#[repr(C)]
#[derive(Debug)]
pub struct CoppProfile3rd {
pub a: CoppVecF64,
pub b: CoppVecF64,
pub num_stationary_start: usize,
pub num_stationary_end: usize,
}
impl CoppProfile3rd {
pub(crate) const fn empty() -> Self {
Self {
a: CoppVecF64::empty(),
b: CoppVecF64::empty(),
num_stationary_start: 0,
num_stationary_end: 0,
}
}
pub(crate) fn from_parts(a: Vec<f64>, b: Vec<f64>, num_stationary: (usize, usize)) -> Self {
Self {
a: CoppVecF64::from_vec(a),
b: CoppVecF64::from_vec(b),
num_stationary_start: num_stationary.0,
num_stationary_end: num_stationary.1,
}
}
pub(crate) fn free(self) {
self.a.free();
self.b.free();
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_profile_3rd_free(profile: CoppProfile3rd) {
profile.free();
clear_last_error();
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Topp3Problem {
pub robot: *mut CoppRobot,
pub idx_s_start: usize,
pub a_linearization: CoppSliceF64,
pub a_start: f64,
pub a_final: f64,
pub b_start: f64,
pub b_final: f64,
pub num_stationary_max_start: usize,
pub num_stationary_max_end: usize,
pub a_linearization_floor: f64,
}
impl Topp3Problem {
pub(crate) unsafe fn build_rust<'a>(self) -> Result<RustTopp3Problem<'a>, CoppStatus> {
let robot = unsafe { CoppRobot::robot_mut(self.robot) }.ok_or(CoppStatus::NullPointer)?;
let a_linearization = unsafe { self.a_linearization.as_slice()? };
RustTopp3ProblemBuilder::new(
robot,
self.idx_s_start,
a_linearization,
(self.a_start, self.a_final),
(self.b_start, self.b_final),
)
.with_num_stationary_max_pair((self.num_stationary_max_start, self.num_stationary_max_end))
.with_a_linearization_floor(self.a_linearization_floor)
.build_with_linearization()
.map_err(|error| CoppStatus::from(&error))
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Copp3Problem {
pub robot: *mut CoppRobot,
pub idx_s_start: usize,
pub a_linearization: CoppSliceF64,
pub a_start: f64,
pub a_final: f64,
pub b_start: f64,
pub b_final: f64,
pub num_stationary_max_start: usize,
pub num_stationary_max_end: usize,
pub a_linearization_floor: f64,
pub objectives: *const CoppObjective,
pub num_objectives: usize,
}
impl Copp3Problem {
pub(crate) unsafe fn rust_objectives<'a>(
self,
allow_total_variation_torque: bool,
) -> Result<Vec<RustCoppObjective<'a>>, CoppStatus> {
let objectives = unsafe { objective_slice(self.objectives, self.num_objectives)? };
objectives
.iter()
.map(|objective| {
unsafe { objective.as_rust_objective(allow_total_variation_torque) }
})
.collect()
}
pub(crate) unsafe fn with_rust_problem<R>(
self,
allow_total_variation_torque: bool,
solve: impl for<'a> FnOnce(RustCopp3Problem<'a, CoppTorqueForC>) -> Result<R, CoppStatus>,
) -> Result<R, CoppStatus> {
let robot = unsafe { CoppRobot::robot_mut(self.robot) }.ok_or(CoppStatus::NullPointer)?;
let a_linearization = unsafe { self.a_linearization.as_slice()? };
let objectives = unsafe { self.rust_objectives(allow_total_variation_torque)? };
let problem = RustCopp3ProblemBuilder::new(
robot,
&objectives,
self.idx_s_start,
a_linearization,
(self.a_start, self.a_final),
(self.b_start, self.b_final),
)
.with_num_stationary_max_pair((self.num_stationary_max_start, self.num_stationary_max_end))
.with_a_linearization_floor(self.a_linearization_floor)
.build_with_linearization()
.map_err(|error| CoppStatus::from(&error))?;
solve(problem)
}
}
pub(crate) unsafe fn objective_slice<'a>(
objectives: *const CoppObjective,
num_objectives: usize,
) -> Result<&'a [CoppObjective], CoppStatus> {
if num_objectives == 0 {
return Ok(&[]);
}
if objectives.is_null() {
return Err(CoppStatus::NullPointer);
}
Ok(unsafe { slice::from_raw_parts(objectives, num_objectives) })
}