mirror of
https://github.com/tdulcet/Table-and-Graph-Libs.git
synced 2025-05-05 21:41:12 +08:00
intermediate texture preview
This commit is contained in:
parent
ed5d06d08a
commit
30beea8b75
122
graphs.hpp
122
graphs.hpp
@ -169,6 +169,30 @@ namespace graphs
|
||||
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 color;
|
||||
uint8_t data_point_bitfield; // stores up to 8 data points
|
||||
};
|
||||
|
||||
// Number of columns needed to represent the string
|
||||
// Adapted from: https://stackoverflow.com/a/31124065
|
||||
inline int strcol(const string &str)
|
||||
@ -754,6 +778,104 @@ namespace graphs
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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 = {}) {
|
||||
cout << "Experimental histogram\n";
|
||||
|
||||
// precalc graph span
|
||||
const double x_size = x_max - x_min;
|
||||
const double y_size = y_max - y_min;
|
||||
// need width+height of chosen character set (using bar characters as example)
|
||||
const size_t char_width = 1; // bar supports 1 state per character width
|
||||
const size_t char_height = 8; // bar supports 8 states per character height
|
||||
// calc how many data points we can represent with current character set and width/height
|
||||
const size_t x_points = width * char_width;
|
||||
const size_t y_points = height * char_height;
|
||||
// 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
|
||||
// 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;
|
||||
|
||||
// histogram specific: each bar needs at least one data point
|
||||
if ((double)x_points / x_size < 1) {
|
||||
cerr << "width is too small to fit all histogram bars\n";
|
||||
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
|
||||
vector<size_t> histogram(x_size, 0);
|
||||
for (const auto &x: data) {
|
||||
// check if value is between limits
|
||||
if (x >= x_min && x < x_max) {
|
||||
// calculate index on x-axis
|
||||
const size_t index = x - x_min;
|
||||
// increment height of the bar
|
||||
++histogram[index];
|
||||
}
|
||||
}
|
||||
|
||||
// create 2D array of temporary fragments for the graph
|
||||
vector<fragment> tex(width * height);
|
||||
// insert draw histogram data into texture
|
||||
for (size_t x = 0; x < histogram.size(); x++) {
|
||||
// calc bar position on x-axis
|
||||
const size_t x_pos = x * (x_bar_size + x_bar_spacer);
|
||||
|
||||
// read bar size from histogram
|
||||
const size_t y_histo = histogram[x];
|
||||
// scale to 0-1 range via max bar size
|
||||
const double y_scaled = (double)y_histo / y_size;
|
||||
// scale back up via point size
|
||||
const size_t y_target = y_scaled * (double)y_points;
|
||||
// calc fragment position and remainder for cap
|
||||
const size_t y_tex = y_target / char_height;
|
||||
const size_t y_cap = y_target % char_height;
|
||||
|
||||
// draw bar body
|
||||
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
|
||||
const size_t index = x_pos + (height - 1 - y) * width;
|
||||
tex[index].color.col_4 = aoptions.color;
|
||||
tex[index].data_point_bitfield = 8; // use full height of character
|
||||
}
|
||||
|
||||
// draw bar cap
|
||||
if (y_cap > 0) {
|
||||
// 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;
|
||||
tex[index].color.col_4 = aoptions.color;
|
||||
tex[index].data_point_bitfield = y_cap; // use remainder to fill up character
|
||||
}
|
||||
}
|
||||
|
||||
// draw graph for experimental preview purposes only
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
const size_t index = x + y * width;
|
||||
const auto& frag = tex[index];
|
||||
// draw fragment
|
||||
cout << colors[frag.color.col_4];
|
||||
cout << bars[frag.data_point_bitfield];
|
||||
cout << colors[0];
|
||||
}
|
||||
cout << '\n';
|
||||
}
|
||||
}
|
||||
// EXPERIMENTAL END
|
||||
|
||||
template <typename T>
|
||||
int histogram(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &aarray, const options &aoptions = {})
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user