/*******************************************************
* Copyright (c) 2014, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
* The complete license agreement can be obtained at:
* http://arrayfire.com/licenses/BSD-3-Clause
********************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using af::dim4;
using arrayfire::common::ForgeManager;
using arrayfire::common::ForgeModule;
using arrayfire::common::forgePlugin;
using arrayfire::common::getFGMarker;
using arrayfire::common::getGLType;
using arrayfire::common::makeContextCurrent;
using arrayfire::common::step_round;
using detail::Array;
using detail::copy_plot;
using detail::forgeManager;
using detail::reduce;
using detail::schar;
using detail::uchar;
using detail::uint;
using detail::ushort;
// Requires in_ to be in either [order, n] or [n, order] format
template
fg_chart setup_plot(fg_window window, const af_array in_,
const af_cell* const props, fg_plot_type ptype,
fg_marker_type mtype) {
ForgeModule& _ = forgePlugin();
Array in = getArray(in_);
af::dim4 dims = in.dims();
DIM_ASSERT(1, dims.ndims() == 2);
DIM_ASSERT(1, (dims[0] == order || dims[1] == order));
// The data expected by backend is 2D [order, n]
if (dims[1] == order) { in = transpose(in, false); }
af::dim4 tdims = in.dims(); // transposed dimensions
ForgeManager& fgMngr = forgeManager();
// Get the chart for the current grid position (if any)
fg_chart chart = NULL;
fg_chart_type ctype = order == 2 ? FG_CHART_2D : FG_CHART_3D;
if (props->col > -1 && props->row > -1) {
chart = fgMngr.getChart(window, props->row, props->col, ctype);
} else {
chart = fgMngr.getChart(window, 0, 0, ctype);
}
fg_plot plot =
fgMngr.getPlot(chart, tdims[1], getGLType(), ptype, mtype);
// ArrayFire LOGO Orange shade
FG_CHECK(_.fg_set_plot_color(plot, 0.929f, 0.529f, 0.212f, 1.0));
// If chart axes limits do not have a manual override
// then compute and set axes limits
if (!fgMngr.getChartAxesOverride(chart)) {
float cmin[3], cmax[3];
T dmin[3], dmax[3];
FG_CHECK(_.fg_get_chart_axes_limits(
&cmin[0], &cmax[0], &cmin[1], &cmax[1], &cmin[2], &cmax[2], chart));
copyData(dmin, reduce(in, 1));
copyData(dmax, reduce(in, 1));
if (cmin[0] == 0 && cmax[0] == 0 && cmin[1] == 0 && cmax[1] == 0 &&
cmin[2] == 0 && cmax[2] == 0) {
// No previous limits. Set without checking
cmin[0] = step_round(dmin[0], false);
cmax[0] = step_round(dmax[0], true);
cmin[1] = step_round(dmin[1], false);
cmax[1] = step_round(dmax[1], true);
if (order == 3) { cmin[2] = step_round(dmin[2], false); }
if (order == 3) { cmax[2] = step_round(dmax[2], true); }
} else {
if (cmin[0] > dmin[0]) { cmin[0] = step_round(dmin[0], false); }
if (cmax[0] < dmax[0]) { cmax[0] = step_round(dmax[0], true); }
if (cmin[1] > dmin[1]) { cmin[1] = step_round(dmin[1], false); }
if (cmax[1] < dmax[1]) { cmax[1] = step_round(dmax[1], true); }
if (order == 3) {
if (cmin[2] > dmin[2]) { cmin[2] = step_round(dmin[2], false); }
if (cmax[2] < dmax[2]) { cmax[2] = step_round(dmax[2], true); }
}
}
FG_CHECK(_.fg_set_chart_axes_limits(chart, cmin[0], cmax[0], cmin[1],
cmax[1], cmin[2], cmax[2]));
}
copy_plot(in, plot);
return chart;
}
template
fg_chart setup_plot(fg_window window, const af_array in_, const int order,
const af_cell* const props, fg_plot_type ptype,
fg_marker_type mtype) {
if (order == 2) {
return setup_plot(window, in_, props, ptype, mtype);
}
if (order == 3) {
return setup_plot(window, in_, props, ptype, mtype);
}
// Dummy to avoid warnings
return NULL;
}
af_err plotWrapper(const af_window window, const af_array in,
const int order_dim, const af_cell* const props,
fg_plot_type ptype = FG_PLOT_LINE,
fg_marker_type marker = FG_MARKER_NONE) {
try {
if (window == 0) { AF_ERROR("Not a valid window", AF_ERR_INTERNAL); }
const ArrayInfo& info = getInfo(in);
af::dim4 dims = info.dims();
af_dtype type = info.getType();
DIM_ASSERT(0, dims.ndims() == 2);
DIM_ASSERT(0, dims[order_dim] == 2 || dims[order_dim] == 3);
makeContextCurrent(window);
fg_chart chart = NULL;
switch (type) {
case f32:
chart = setup_plot(window, in, dims[order_dim], props,
ptype, marker);
break;
case s32:
chart = setup_plot(window, in, dims[order_dim], props,
ptype, marker);
break;
case u32:
chart = setup_plot(window, in, dims[order_dim], props,
ptype, marker);
break;
case s16:
chart = setup_plot(window, in, dims[order_dim], props,
ptype, marker);
break;
case u16:
chart = setup_plot(window, in, dims[order_dim], props,
ptype, marker);
break;
case s8:
chart = setup_plot(window, in, dims[order_dim], props,
ptype, marker);
break;
case u8:
chart = setup_plot(window, in, dims[order_dim], props,
ptype, marker);
break;
default: TYPE_ERROR(1, type);
}
auto gridDims = forgeManager().getWindowGrid(window);
ForgeModule& _ = forgePlugin();
if (props->col > -1 && props->row > -1) {
FG_CHECK(_.fg_draw_chart_to_cell(
window, gridDims.first, gridDims.second,
props->row * gridDims.second + props->col, chart,
props->title));
} else {
FG_CHECK(_.fg_draw_chart(window, chart));
}
}
CATCHALL;
return AF_SUCCESS;
}
af_err plotWrapper(const af_window window, const af_array X, const af_array Y,
const af_array Z, const af_cell* const props,
fg_plot_type ptype = FG_PLOT_LINE,
fg_marker_type marker = FG_MARKER_NONE) {
try {
if (window == 0) { AF_ERROR("Not a valid window", AF_ERR_INTERNAL); }
const ArrayInfo& xInfo = getInfo(X);
const af::dim4& xDims = xInfo.dims();
af_dtype xType = xInfo.getType();
const ArrayInfo& yInfo = getInfo(Y);
const af::dim4& yDims = yInfo.dims();
af_dtype yType = yInfo.getType();
const ArrayInfo& zInfo = getInfo(Z);
const af::dim4& zDims = zInfo.dims();
af_dtype zType = zInfo.getType();
DIM_ASSERT(0, xDims == yDims);
DIM_ASSERT(0, xDims == zDims);
DIM_ASSERT(0, xInfo.isVector());
TYPE_ASSERT(xType == yType);
TYPE_ASSERT(xType == zType);
// Join for set up vector
af_array in = 0;
af_array pIn[] = {X, Y, Z};
AF_CHECK(af_join_many(&in, 1, 3, pIn));
makeContextCurrent(window);
fg_chart chart = NULL;
switch (xType) {
case f32:
chart = setup_plot(window, in, 3, props, ptype, marker);
break;
case s32:
chart = setup_plot(window, in, 3, props, ptype, marker);
break;
case u32:
chart = setup_plot(window, in, 3, props, ptype, marker);
break;
case s16:
chart = setup_plot(window, in, 3, props, ptype, marker);
break;
case u16:
chart = setup_plot(window, in, 3, props, ptype, marker);
break;
case s8:
chart = setup_plot(window, in, 3, props, ptype, marker);
break;
case u8:
chart = setup_plot(window, in, 3, props, ptype, marker);
break;
default: TYPE_ERROR(1, xType);
}
auto gridDims = forgeManager().getWindowGrid(window);
ForgeModule& _ = forgePlugin();
if (props->col > -1 && props->row > -1) {
FG_CHECK(_.fg_draw_chart_to_cell(
window, gridDims.first, gridDims.second,
props->row * gridDims.second + props->col, chart,
props->title));
} else {
FG_CHECK(_.fg_draw_chart(window, chart));
}
AF_CHECK(af_release_array(in));
}
CATCHALL;
return AF_SUCCESS;
}
af_err plotWrapper(const af_window window, const af_array X, const af_array Y,
const af_cell* const props,
fg_plot_type ptype = FG_PLOT_LINE,
fg_marker_type marker = FG_MARKER_NONE) {
try {
if (window == 0) { AF_ERROR("Not a valid window", AF_ERR_INTERNAL); }
const ArrayInfo& xInfo = getInfo(X);
const af::dim4& xDims = xInfo.dims();
af_dtype xType = xInfo.getType();
const ArrayInfo& yInfo = getInfo(Y);
const af::dim4& yDims = yInfo.dims();
af_dtype yType = yInfo.getType();
DIM_ASSERT(0, xDims == yDims);
DIM_ASSERT(0, xInfo.isVector());
TYPE_ASSERT(xType == yType);
// Join for set up vector
af_array in = 0;
AF_CHECK(af_join(&in, 1, X, Y));
makeContextCurrent(window);
fg_chart chart = NULL;
switch (xType) {
case f32:
chart = setup_plot(window, in, 2, props, ptype, marker);
break;
case s32:
chart = setup_plot(window, in, 2, props, ptype, marker);
break;
case u32:
chart = setup_plot(window, in, 2, props, ptype, marker);
break;
case s16:
chart = setup_plot(window, in, 2, props, ptype, marker);
break;
case u16:
chart = setup_plot(window, in, 2, props, ptype, marker);
break;
case s8:
chart = setup_plot(window, in, 2, props, ptype, marker);
break;
case u8:
chart = setup_plot(window, in, 2, props, ptype, marker);
break;
default: TYPE_ERROR(1, xType);
}
auto gridDims = forgeManager().getWindowGrid(window);
ForgeModule& _ = forgePlugin();
if (props->col > -1 && props->row > -1) {
FG_CHECK(_.fg_draw_chart_to_cell(
window, gridDims.first, gridDims.second,
props->row * gridDims.second + props->col, chart,
props->title));
} else {
FG_CHECK(_.fg_draw_chart(window, chart));
}
AF_CHECK(af_release_array(in));
}
CATCHALL;
return AF_SUCCESS;
}
// Plot API
af_err af_draw_plot_nd(const af_window wind, const af_array in,
const af_cell* const props) {
return plotWrapper(wind, in, 1, props);
}
af_err af_draw_plot_2d(const af_window wind, const af_array X, const af_array Y,
const af_cell* const props) {
return plotWrapper(wind, X, Y, props);
}
af_err af_draw_plot_3d(const af_window wind, const af_array X, const af_array Y,
const af_array Z, const af_cell* const props) {
return plotWrapper(wind, X, Y, Z, props);
}
// Deprecated Plot API
af_err af_draw_plot(const af_window wind, const af_array X, const af_array Y,
const af_cell* const props) {
return plotWrapper(wind, X, Y, props);
}
af_err af_draw_plot3(const af_window wind, const af_array P,
const af_cell* const props) {
try {
const ArrayInfo& info = getInfo(P);
af::dim4 dims = info.dims();
if (dims.ndims() == 2 && dims[1] == 3) {
return plotWrapper(wind, P, 1, props);
}
if (dims.ndims() == 2 && dims[0] == 3) {
return plotWrapper(wind, P, 0, props);
} else if (dims.ndims() == 1 && dims[0] % 3 == 0) {
dim4 rdims(dims.elements() / 3, 3, 1, 1);
af_array in = 0;
AF_CHECK(af_moddims(&in, P, rdims.ndims(), rdims.get()));
af_err err = plotWrapper(wind, in, 1, props);
AF_CHECK(af_release_array(in));
return err;
} else {
AF_RETURN_ERROR(
"Input needs to be either [n, 3] or [3, n] or [3n, 1]",
AF_ERR_SIZE);
}
}
CATCHALL;
return AF_SUCCESS;
}
// Scatter API
af_err af_draw_scatter_nd(const af_window wind, const af_array in,
const af_marker_type af_marker,
const af_cell* const props) {
try {
fg_marker_type fg_marker = getFGMarker(af_marker);
return plotWrapper(wind, in, 1, props, FG_PLOT_SCATTER, fg_marker);
}
CATCHALL;
}
af_err af_draw_scatter_2d(const af_window wind, const af_array X,
const af_array Y, const af_marker_type af_marker,
const af_cell* const props) {
try {
fg_marker_type fg_marker = getFGMarker(af_marker);
return plotWrapper(wind, X, Y, props, FG_PLOT_SCATTER, fg_marker);
}
CATCHALL;
}
af_err af_draw_scatter_3d(const af_window wind, const af_array X,
const af_array Y, const af_array Z,
const af_marker_type af_marker,
const af_cell* const props) {
try {
fg_marker_type fg_marker = getFGMarker(af_marker);
return plotWrapper(wind, X, Y, Z, props, FG_PLOT_SCATTER, fg_marker);
}
CATCHALL;
}
// Deprecated Scatter API
af_err af_draw_scatter(const af_window wind, const af_array X, const af_array Y,
const af_marker_type af_marker,
const af_cell* const props) {
try {
fg_marker_type fg_marker = getFGMarker(af_marker);
return plotWrapper(wind, X, Y, props, FG_PLOT_SCATTER, fg_marker);
}
CATCHALL;
}
af_err af_draw_scatter3(const af_window wind, const af_array P,
const af_marker_type af_marker,
const af_cell* const props) {
try {
fg_marker_type fg_marker = getFGMarker(af_marker);
const ArrayInfo& info = getInfo(P);
af::dim4 dims = info.dims();
if (dims.ndims() == 2 && dims[1] == 3) {
return plotWrapper(wind, P, 1, props, FG_PLOT_SCATTER, fg_marker);
}
if (dims.ndims() == 2 && dims[0] == 3) {
return plotWrapper(wind, P, 0, props, FG_PLOT_SCATTER, fg_marker);
} else if (dims.ndims() == 1 && dims[0] % 3 == 0) {
dim4 rdims(dims.elements() / 3, 3, 1, 1);
af_array in = 0;
AF_CHECK(af_moddims(&in, P, rdims.ndims(), rdims.get()));
af_err err =
plotWrapper(wind, in, 1, props, FG_PLOT_SCATTER, fg_marker);
AF_CHECK(af_release_array(in));
return err;
} else {
AF_RETURN_ERROR(
"Input needs to be either [n, 3] or [3, n] or [3n, 1]",
AF_ERR_SIZE);
}
}
CATCHALL;
return AF_SUCCESS;
}