use super::core::{
af_array, af_window, AfError, Array, ColorMap, HasAfEnum, MarkerType, HANDLE_ERROR,
};
use libc::{c_char, c_double, c_float, c_int, c_uint};
use std::ffi::CString;
use std::ptr;
#[repr(C)]
struct af_cell {
pub row: c_int,
pub col: c_int,
pub title: *const c_char,
pub cmap: c_uint,
}
extern "C" {
fn af_create_window(out: *mut af_window, w: c_int, h: c_int, title: *const c_char) -> c_int;
fn af_set_position(wnd: af_window, x: c_uint, y: c_uint) -> c_int;
fn af_set_title(wnd: af_window, title: *const c_char) -> c_int;
fn af_set_size(wnd: af_window, w: c_uint, h: c_uint) -> c_int;
fn af_set_visibility(wnd: af_window, is_visible: bool) -> c_int;
fn af_set_axes_titles(
wnd: af_window,
xtitle: *const c_char,
ytitle: *const c_char,
ztitle: *const c_char,
props: *const af_cell,
) -> c_int;
fn af_set_axes_label_format(
wnd: af_window,
xformat: *const c_char,
yformat: *const c_char,
zformat: *const c_char,
props: *const af_cell,
) -> c_int;
fn af_set_axes_limits_compute(
wnd: af_window,
x: af_array,
y: af_array,
z: af_array,
exact: bool,
props: *const af_cell,
) -> c_int;
fn af_set_axes_limits_2d(
wnd: af_window,
xmin: c_float,
xmax: c_float,
ymin: c_float,
ymax: c_float,
exact: bool,
props: *const af_cell,
) -> c_int;
fn af_set_axes_limits_3d(
wnd: af_window,
xmin: c_float,
xmax: c_float,
ymin: c_float,
ymax: c_float,
zmin: c_float,
zmax: c_float,
exact: bool,
props: *const af_cell,
) -> c_int;
fn af_draw_image(wnd: af_window, arr: af_array, props: *const af_cell) -> c_int;
fn af_draw_hist(
wnd: af_window,
x: af_array,
minval: c_double,
maxval: c_double,
props: *const af_cell,
) -> c_int;
fn af_draw_surface(
wnd: af_window,
xvals: af_array,
yvals: af_array,
S: af_array,
props: *const af_cell,
) -> c_int;
fn af_draw_plot_2d(wnd: af_window, x: af_array, y: af_array, props: *const af_cell) -> c_int;
fn af_draw_plot_3d(
wnd: af_window,
x: af_array,
y: af_array,
z: af_array,
props: *const af_cell,
) -> c_int;
fn af_draw_plot_nd(wnd: af_window, P: af_array, props: *const af_cell) -> c_int;
fn af_draw_scatter_2d(
wnd: af_window,
x: af_array,
y: af_array,
marker: c_uint,
props: *const af_cell,
) -> c_int;
fn af_draw_scatter_3d(
wnd: af_window,
x: af_array,
y: af_array,
z: af_array,
marker: c_uint,
props: *const af_cell,
) -> c_int;
fn af_draw_scatter_nd(
wnd: af_window,
P: af_array,
marker: c_uint,
props: *const af_cell,
) -> c_int;
fn af_draw_vector_field_2d(
wnd: af_window,
xpnts: af_array,
ypnts: af_array,
xdirs: af_array,
ydirs: af_array,
props: *const af_cell,
) -> c_int;
fn af_draw_vector_field_3d(
wnd: af_window,
xpnts: af_array,
ypnts: af_array,
xdirs: af_array,
ydirs: af_array,
zdirs: af_array,
zdirs: af_array,
props: *const af_cell,
) -> c_int;
fn af_draw_vector_field_nd(
wnd: af_window,
pnts: af_array,
dirs: af_array,
props: *const af_cell,
) -> c_int;
fn af_grid(wnd: af_window, rows: c_int, cols: c_int) -> c_int;
fn af_show(wnd: af_window) -> c_int;
fn af_is_window_closed(out: *mut bool, wnd: af_window) -> c_int;
fn af_destroy_window(wnd: af_window) -> c_int;
}
#[derive(Clone)]
pub struct Window {
handle: af_window,
row: i32,
col: i32,
cmap: ColorMap,
}
impl Drop for Window {
fn drop(&mut self) {
unsafe {
let err_val = af_destroy_window(self.handle);
match err_val {
0 => (),
_ => panic!(
"Window object destruction failed with error code: {}",
err_val
),
}
}
}
}
impl Window {
#[allow(clippy::match_wild_err_arm)]
pub fn new(width: i32, height: i32, title: String) -> Self {
unsafe {
let cstr_ret = CString::new(title);
match cstr_ret {
Ok(cstr) => {
let mut temp: af_window = std::ptr::null_mut();
let err_val =
af_create_window(&mut temp as *mut af_window, width, height, cstr.as_ptr());
HANDLE_ERROR(AfError::from(err_val));
Window {
handle: temp,
row: -1,
col: -1,
cmap: ColorMap::DEFAULT,
}
}
Err(_) => {
panic!("String creation failed while prepping params for window creation.")
}
}
}
}
pub fn set_position(&self, x: u32, y: u32) {
unsafe {
let err_val = af_set_position(self.handle, x, y);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_title(&self, title: String) {
unsafe {
let cstr_ret = CString::new(title);
match cstr_ret {
Ok(cstr) => {
let err_val = af_set_title(self.handle, cstr.as_ptr());
HANDLE_ERROR(AfError::from(err_val));
}
Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL),
}
}
}
pub fn set_visibility(&self, is_visible: bool) {
unsafe {
let err_val = af_set_visibility(self.handle, is_visible);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_size(&self, w: u32, h: u32) {
unsafe {
let err_val = af_set_size(self.handle, w, h);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_colormap(&mut self, cmap: ColorMap) {
self.cmap = cmap;
}
pub fn is_closed(&self) -> bool {
unsafe {
let mut temp: bool = true;
let err_val = af_is_window_closed(&mut temp as *mut bool, self.handle);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
pub fn grid(&self, rows: i32, cols: i32) {
unsafe {
let err_val = af_grid(self.handle, rows, cols);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn show(&mut self) {
unsafe {
let err_val = af_show(self.handle);
HANDLE_ERROR(AfError::from(err_val));
self.row = -1;
self.col = -1;
}
}
pub fn set_view(&mut self, r: i32, c: i32) {
self.row = r;
self.col = c;
}
pub fn set_axes_titles(&mut self, xlabel: String, ylabel: String, zlabel: String) {
let cprops = af_cell {
row: self.row,
col: self.col,
title: ptr::null(),
cmap: self.cmap as u32,
};
let xstr = CString::new(xlabel).unwrap();
let ystr = CString::new(ylabel).unwrap();
let zstr = CString::new(zlabel).unwrap();
unsafe {
let err_val = af_set_axes_titles(
self.handle,
xstr.as_ptr(),
ystr.as_ptr(),
zstr.as_ptr(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_axes_label_format(
&mut self,
xlabel_format: String,
ylabel_format: String,
zlabel_format: String,
) {
let cprops = af_cell {
row: self.row,
col: self.col,
title: ptr::null(),
cmap: self.cmap as u32,
};
let xstr = CString::new(xlabel_format).unwrap();
let ystr = CString::new(ylabel_format).unwrap();
let zstr = CString::new(zlabel_format).unwrap();
unsafe {
let err_val = af_set_axes_label_format(
self.handle,
xstr.as_ptr(),
ystr.as_ptr(),
zstr.as_ptr(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_axes_label_formats(&mut self, xformat: String, yformat: String, zformat: String) {
let cprops = af_cell {
row: self.row,
col: self.col,
title: ptr::null(),
cmap: self.cmap as u32,
};
let xstr = CString::new(xformat).unwrap();
let ystr = CString::new(yformat).unwrap();
let zstr = CString::new(zformat).unwrap();
unsafe {
let err_val = af_set_axes_titles(
self.handle,
xstr.as_ptr(),
ystr.as_ptr(),
zstr.as_ptr(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_axes_limits_compute<T>(
&mut self,
xrange: &Array<T>,
yrange: &Array<T>,
zrange: Option<&Array<T>>,
exact: bool,
) where
T: HasAfEnum,
{
let cprops = af_cell {
row: self.row,
col: self.col,
title: ptr::null(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_set_axes_limits_compute(
self.handle,
xrange.get(),
yrange.get(),
match zrange {
Some(z) => z.get(),
None => std::ptr::null_mut(),
},
exact,
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_axes_limits_2d(&mut self, xmin: f32, xmax: f32, ymin: f32, ymax: f32, exact: bool) {
let cprops = af_cell {
row: self.row,
col: self.col,
title: ptr::null(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_set_axes_limits_2d(
self.handle,
xmin,
xmax,
ymin,
ymax,
exact,
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
#[allow(clippy::too_many_arguments)]
pub fn set_axes_limits_3d(
&mut self,
xmin: f32,
xmax: f32,
ymin: f32,
ymax: f32,
zmin: f32,
zmax: f32,
exact: bool,
) {
let cprops = af_cell {
row: self.row,
col: self.col,
title: ptr::null(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_set_axes_limits_3d(
self.handle,
xmin,
xmax,
ymin,
ymax,
zmin,
zmax,
exact,
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_image<T>(&self, input: &Array<T>, title: Option<String>)
where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_image(self.handle, input.get(), &cprops as *const af_cell);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_plot2<T>(&self, x: &Array<T>, y: &Array<T>, title: Option<String>)
where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_plot_2d(self.handle, x.get(), y.get(), &cprops as *const af_cell);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_plot3<T>(&self, x: &Array<T>, y: &Array<T>, z: &Array<T>, title: Option<String>)
where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_plot_3d(
self.handle,
x.get(),
y.get(),
z.get(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_plot<T>(&self, points: &Array<T>, title: Option<String>)
where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_plot_nd(self.handle, points.get(), &cprops as *const af_cell);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_hist<T>(&self, hst: &Array<T>, minval: f64, maxval: f64, title: Option<String>)
where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_hist(
self.handle,
hst.get(),
minval,
maxval,
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_surface<T>(
&self,
xvals: &Array<T>,
yvals: &Array<T>,
zvals: &Array<T>,
title: Option<String>,
) where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_surface(
self.handle,
xvals.get(),
yvals.get(),
zvals.get(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_scatter2<T>(
&self,
xvals: &Array<T>,
yvals: &Array<T>,
marker: MarkerType,
title: Option<String>,
) where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_scatter_2d(
self.handle,
xvals.get(),
yvals.get(),
marker as c_uint,
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_scatter3<T>(
&self,
xvals: &Array<T>,
yvals: &Array<T>,
zvals: &Array<T>,
marker: MarkerType,
title: Option<String>,
) where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_scatter_3d(
self.handle,
xvals.get(),
yvals.get(),
zvals.get(),
marker as c_uint,
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_scatter<T>(&self, vals: &Array<T>, marker: MarkerType, title: Option<String>)
where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_scatter_nd(
self.handle,
vals.get(),
marker as c_uint,
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_vector_field2<T>(
&self,
xpnts: &Array<T>,
ypnts: &Array<T>,
xdirs: &Array<T>,
ydirs: &Array<T>,
title: Option<String>,
) where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_vector_field_2d(
self.handle,
xpnts.get(),
ypnts.get(),
xdirs.get(),
ydirs.get(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
#[allow(clippy::too_many_arguments)]
pub fn draw_vector_field3<T>(
&self,
xpnts: &Array<T>,
ypnts: &Array<T>,
zpnts: &Array<T>,
xdirs: &Array<T>,
ydirs: &Array<T>,
zdirs: &Array<T>,
title: Option<String>,
) where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_vector_field_3d(
self.handle,
xpnts.get(),
ypnts.get(),
zpnts.get(),
xdirs.get(),
ydirs.get(),
zdirs.get(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn draw_vector_field<T>(
&self,
points: &Array<T>,
directions: &Array<T>,
title: Option<String>,
) where
T: HasAfEnum,
{
let tstr = match title {
Some(s) => s,
None => format!("Cell({},{}))", self.col, self.row),
};
let tstr = CString::new(tstr).unwrap();
let cprops = af_cell {
row: self.row,
col: self.col,
title: tstr.as_ptr(),
cmap: self.cmap as u32,
};
unsafe {
let err_val = af_draw_vector_field_nd(
self.handle,
points.get(),
directions.get(),
&cprops as *const af_cell,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
}