mirror of
https://github.com/tdulcet/Table-and-Graph-Libs.git
synced 2025-06-24 19:31:42 +08:00
consolidate options
This commit is contained in:
parent
366512d614
commit
316d2105d3
124
graphs.hpp
124
graphs.hpp
@ -54,7 +54,7 @@ namespace graphs
|
|||||||
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "} // No border
|
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "} // No border
|
||||||
};
|
};
|
||||||
|
|
||||||
enum color_type
|
enum color_type: uint8_t
|
||||||
{
|
{
|
||||||
color_default,
|
color_default,
|
||||||
color_black,
|
color_black,
|
||||||
@ -169,29 +169,7 @@ namespace graphs
|
|||||||
bool check = true;
|
bool check = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Structure for 24-bit true colors
|
|
||||||
struct true_color
|
|
||||||
{
|
|
||||||
uint8_t red;
|
|
||||||
uint8_t green;
|
|
||||||
uint8_t blue;
|
|
||||||
};
|
|
||||||
// Using the existing color_type enum for the 4-bit colors (not using std::variant due to its larger size)
|
|
||||||
using color = union {
|
|
||||||
color_type col_4;
|
|
||||||
uint8_t col_8;
|
|
||||||
struct { // 24-bit true color
|
|
||||||
uint8_t r;
|
|
||||||
uint8_t g;
|
|
||||||
uint8_t b;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
// Intermediate fragment representation potentially holding multiple pixels (e.g. 2x4 as braille)
|
|
||||||
// most optimal representation possible with only 4 bytes in size, applicable for all types of characters
|
|
||||||
struct fragment {
|
|
||||||
color col;
|
|
||||||
uint8_t data_point_bitfield; // stores up to 8 data points
|
|
||||||
};
|
|
||||||
|
|
||||||
// Number of columns needed to represent the string
|
// Number of columns needed to represent the string
|
||||||
// Adapted from: https://stackoverflow.com/a/31124065
|
// Adapted from: https://stackoverflow.com/a/31124065
|
||||||
@ -779,10 +757,70 @@ namespace graphs
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXPERIMENTAL BEG
|
// EXPERIMENTAL BEG
|
||||||
template <typename T> // TODO: remove templating?
|
|
||||||
void histogram_experimental(size_t height, size_t width, double x_min, double x_max, double y_min, double y_max, const T &data, const options &aoptions = {}) {
|
// Using the existing color_type enum for the 4-bit colors (not using std::variant due to its larger size)
|
||||||
|
union Color {
|
||||||
|
color_type col_4; // 4-bit color
|
||||||
|
uint8_t col_8; // 8-bit color
|
||||||
|
struct {
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
} col_24; // 24-bit true color
|
||||||
|
};
|
||||||
|
enum class ColorBits: uint8_t { e4, e8, e24 };
|
||||||
|
|
||||||
|
// Intermediate fragment representation potentially holding multiple pixels (e.g. 2x4 as braille)
|
||||||
|
// most optimal representation possible with only 4 bytes in size, applicable for all types of characters
|
||||||
|
struct Fragment {
|
||||||
|
Color color;
|
||||||
|
uint8_t data; // stores up to 8 data points or up to 255 values
|
||||||
|
};
|
||||||
|
struct Options {
|
||||||
|
size_t width = 0; // Width in terminal characters. Set to 0 for automatic size based on terminal.
|
||||||
|
size_t height = 0; // Height in terminal characters. Set to 0 for automatic size based on terminal.
|
||||||
|
|
||||||
|
struct Axis {
|
||||||
|
double min = 0; // Start of axis. Set to 0 for automatic size based on data.
|
||||||
|
double max = 0; // End of axis. Set to 0 for automatic size based on data.
|
||||||
|
bool enabled = true;
|
||||||
|
bool label = true;
|
||||||
|
bool ticks = true;
|
||||||
|
bool tick_labels = true;
|
||||||
|
units_type tick_label_type = units_fracts;
|
||||||
|
};
|
||||||
|
Axis x = {};
|
||||||
|
Axis y = {};
|
||||||
|
|
||||||
|
type_type character_set = type_braille;
|
||||||
|
style_type style = style_light;
|
||||||
|
ColorBits color_type = ColorBits::e4;
|
||||||
|
bool validate = true; // validate sizes for graph draw
|
||||||
|
bool border = false;
|
||||||
|
|
||||||
|
struct Histogram {
|
||||||
|
size_t bar_width = 1; // size of each bar in x-axis (in data points, e.g. braille has width of 2 per terminal character)
|
||||||
|
};
|
||||||
|
// Union for different graph type options
|
||||||
|
union {
|
||||||
|
Histogram histogram;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream &ostr = cout;
|
||||||
|
const char *title = nullptr;
|
||||||
|
};
|
||||||
|
template <typename T>
|
||||||
|
void histogram_experimental(const Options& options, const T &data) {
|
||||||
cout << "Experimental histogram\n";
|
cout << "Experimental histogram\n";
|
||||||
|
|
||||||
|
// TODO: automatically set sizes if stuff is 0
|
||||||
|
const double x_max = options.x.max;
|
||||||
|
const double x_min = options.x.min;
|
||||||
|
const double y_max = options.y.max;
|
||||||
|
const double y_min = options.y.min;
|
||||||
|
const size_t width = options.width;
|
||||||
|
const size_t height = options.height;
|
||||||
|
|
||||||
// precalc graph span
|
// precalc graph span
|
||||||
const double x_size = x_max - x_min;
|
const double x_size = x_max - x_min;
|
||||||
const double y_size = y_max - y_min;
|
const double y_size = y_max - y_min;
|
||||||
@ -793,7 +831,7 @@ namespace graphs
|
|||||||
const size_t x_points = width * char_width;
|
const size_t x_points = width * char_width;
|
||||||
const size_t y_points = height * char_height;
|
const size_t y_points = height * char_height;
|
||||||
// for histograms, every sample needs at least one data point to occupy in x
|
// for histograms, every sample needs at least one data point to occupy in x
|
||||||
const size_t x_bar_size = 1; // temporarily fixed to 1
|
const size_t x_bar_size = options.histogram.bar_width;
|
||||||
// given the x_bar_size (which should be exposed as an option), see how many points will be placed between bars
|
// given the x_bar_size (which should be exposed as an option), see how many points will be placed between bars
|
||||||
const double x_bar_spacer = (double)x_points / ((double)x_bar_size * x_size) - 1;
|
const double x_bar_spacer = (double)x_points / ((double)x_bar_size * x_size) - 1;
|
||||||
|
|
||||||
@ -803,18 +841,6 @@ namespace graphs
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cout << "width : " << width << '\n';
|
|
||||||
cout << "height: " << height << '\n';
|
|
||||||
cout << "x_size: " << x_size << '\n';
|
|
||||||
cout << "y_size: " << y_size << '\n';
|
|
||||||
cout << '\n';
|
|
||||||
cout << "char_width: " << char_width << '\n';
|
|
||||||
cout << "char_height: " << char_height << '\n';
|
|
||||||
cout << "x_points: " << x_points << '\n';
|
|
||||||
cout << "y_points: " << y_points << '\n';
|
|
||||||
cout << "x_bar_size: " << x_bar_size << '\n';
|
|
||||||
cout << "x_bar_spacer: " << x_bar_spacer << '\n';
|
|
||||||
|
|
||||||
// simple histogram as vector of sample counts
|
// simple histogram as vector of sample counts
|
||||||
vector<size_t> histogram(x_size, 0);
|
vector<size_t> histogram(x_size, 0);
|
||||||
for (const auto &x: data) {
|
for (const auto &x: data) {
|
||||||
@ -827,8 +853,8 @@ namespace graphs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create 2D array of temporary fragments for the graph
|
// create 2D array of temporary Fragments for the graph
|
||||||
vector<fragment> tex(width * height);
|
vector<Fragment> tex(width * height);
|
||||||
// insert draw histogram data into texture
|
// insert draw histogram data into texture
|
||||||
for (size_t x = 0; x < histogram.size(); x++) {
|
for (size_t x = 0; x < histogram.size(); x++) {
|
||||||
// calc bar position on x-axis
|
// calc bar position on x-axis
|
||||||
@ -840,7 +866,7 @@ namespace graphs
|
|||||||
const double y_scaled = (double)y_histo / y_size;
|
const double y_scaled = (double)y_histo / y_size;
|
||||||
// scale back up via point size
|
// scale back up via point size
|
||||||
const size_t y_target = y_scaled * (double)y_points;
|
const size_t y_target = y_scaled * (double)y_points;
|
||||||
// calc fragment position and remainder for cap
|
// calc Fragment position and remainder for cap
|
||||||
const size_t y_tex = y_target / char_height;
|
const size_t y_tex = y_target / char_height;
|
||||||
const size_t y_cap = y_target % char_height;
|
const size_t y_cap = y_target % char_height;
|
||||||
|
|
||||||
@ -848,16 +874,16 @@ namespace graphs
|
|||||||
for (size_t y = 0; y < y_tex; y++) {
|
for (size_t y = 0; y < y_tex; y++) {
|
||||||
// in texture, y=0 is at the top, so we need to invert the y-axis
|
// in texture, y=0 is at the top, so we need to invert the y-axis
|
||||||
const size_t index = x_pos + (height - 1 - y) * width;
|
const size_t index = x_pos + (height - 1 - y) * width;
|
||||||
tex[index].col.col_4 = aoptions.color;
|
tex[index].color.col_4 = color_red;
|
||||||
tex[index].data_point_bitfield = 8; // use full height of character
|
tex[index].data = 8; // use full height of character
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw bar cap
|
// draw bar cap
|
||||||
if (y_cap > 0) {
|
if (y_cap > 0) {
|
||||||
// in texture, y=0 is at the top, so we need to invert the y-axis
|
// in texture, y=0 is at the top, so we need to invert the y-axis
|
||||||
const size_t index = x_pos + (height - 1 - y_tex) * width;
|
const size_t index = x_pos + (height - 1 - y_tex) * width;
|
||||||
tex[index].col.col_4 = aoptions.color;
|
tex[index].color.col_4 = color_red;
|
||||||
tex[index].data_point_bitfield = y_cap; // use remainder to fill up character
|
tex[index].data = y_cap; // use remainder to fill up character
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -866,9 +892,9 @@ namespace graphs
|
|||||||
for (size_t x = 0; x < width; x++) {
|
for (size_t x = 0; x < width; x++) {
|
||||||
const size_t index = x + y * width;
|
const size_t index = x + y * width;
|
||||||
const auto& frag = tex[index];
|
const auto& frag = tex[index];
|
||||||
// draw fragment
|
// draw Fragment
|
||||||
cout << colors[frag.col.col_4];
|
cout << colors[frag.color.col_4];
|
||||||
cout << bars[frag.data_point_bitfield];
|
cout << bars[frag.data];
|
||||||
cout << colors[0];
|
cout << colors[0];
|
||||||
}
|
}
|
||||||
cout << '\n';
|
cout << '\n';
|
||||||
|
Loading…
Reference in New Issue
Block a user