From 5f3eb3dc245493c9e2e9b219e49e9453d1e2aed5 Mon Sep 17 00:00:00 2001 From: nick black Date: Fri, 3 Apr 2020 07:29:19 -0400 Subject: [PATCH] keyplot: add third plot, this one with half blocks #433 --- include/notcurses/notcurses.h | 14 +++---- python/src/notcurses/build_notcurses.py | 20 ++++----- src/input/keyplot.cpp | 19 ++++++--- src/lib/plot.c | 56 +++++++++++++++++++++---- 4 files changed, 75 insertions(+), 34 deletions(-) diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index cd37e362d..f8f7cf230 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2473,15 +2473,11 @@ API int ncmenu_destroy(struct ncmenu* n); typedef enum { NCPLOT_1x1, // full block █ NCPLOT_1x1x4, // shaded full blocks █▓▒░ - NCPLOT_2x1TB, // full/upper blocks █▀ - NCPLOT_2x1BT, // full/lower blocks █▄ - NCPLOT_1x2LR, // left/full blocks ▌█ - NCPLOT_1x2RL, // right/full blocks █▐ - NCPLOT_2x2, // quadrants ▖▘▝▗ - NCPLOT_4x1, // four vert levels █▆▄▂ - NCPLOT_1x4, // four horizontal levels ▎▌▊█ - NCPLOT_8x1, // eight vert levels █▇▆▅▄▃▂▁ - NCPLOT_1x8, // eight horizontal levels ▏▎▍▌▋▊▉█ + NCPLOT_2x1, // full/(upper|left) blocks █▀ + NCPLOT_2x1INV,// full/(lower|right) blocks █▄ + NCPLOT_2x2, // quadrants ▖▘▝▗ ▛ ▜ ▟ ▙ ▘▗ ▖▝ + NCPLOT_4x1, // four vert/horz levels █▆▄▂ / ▎▌▊█ + NCPLOT_8x1, // eight vert/horz levels █▇▆▅▄▃▂▁ / ▏▎▍▌▋▊▉█ NCPLOT_4x2, // 4 rows, 2 cols (braille) ...etc... } ncgridgeom_e; diff --git a/python/src/notcurses/build_notcurses.py b/python/src/notcurses/build_notcurses.py index a82a484cc..0be1d85a3 100644 --- a/python/src/notcurses/build_notcurses.py +++ b/python/src/notcurses/build_notcurses.py @@ -411,18 +411,14 @@ int ncplane_rotate_ccw(struct ncplane* n); void ncplane_translate(const struct ncplane* src, const struct ncplane* dst, int* y, int* x); bool ncplane_translate_abs(const struct ncplane* n, int* y, int* x); typedef enum { - NCPLOT_1x1, - NCPLOT_1x1x4, - NCPLOT_2x1TB, - NCPLOT_2x1BT, - NCPLOT_1x2LR, - NCPLOT_1x2RL, - NCPLOT_2x2, - NCPLOT_4x1, - NCPLOT_1x4, - NCPLOT_8x1, - NCPLOT_1x8, - NCPLOT_4x2, + NCPLOT_1x1, // full block █ + NCPLOT_1x1x4, // shaded full blocks █▓▒░ + NCPLOT_2x1, // full/(upper|left) blocks █▀ + NCPLOT_2x1INV,// full/(lower|right) blocks █▄ + NCPLOT_2x2, // quadrants ▖▘▝▗ ▛ ▜ ▟ ▙ ▘▗ ▖▝ + NCPLOT_4x1, // four vert/horz levels █▆▄▂ / ▎▌▊█ + NCPLOT_8x1, // eight vert/horz levels █▇▆▅▄▃▂▁ / ▏▎▍▌▋▊▉█ + NCPLOT_4x2, // 4 rows, 2 cols (braille) ...etc... } ncgridgeom_e; typedef struct ncplot_options { uint64_t maxchannel; diff --git a/src/input/keyplot.cpp b/src/input/keyplot.cpp index e21e0cf2e..18a6adb6f 100644 --- a/src/input/keyplot.cpp +++ b/src/input/keyplot.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -24,11 +25,18 @@ int main(void){ if(!n->perimeter(tl, tr, bl, br, hl, vl, 0)){ return EXIT_FAILURE; } - ncpp::Plane plotplane{6, 70, 1, 1, nullptr}; + std::vector planes; + planes.emplace_back(6, 70, 1, 1, nullptr); + planes.emplace_back(6, 70, 8, 1, nullptr); + planes.emplace_back(6, 70, 15, 1, nullptr); struct ncplot_options popts{}; popts.rangex = 60; popts.detectdomain = true; - struct ncplot* plot = ncplot_create(plotplane, &popts); + std::array plots; + for(auto i = 0u ; i < plots.size() ; ++i){ + popts.gridtype = static_cast(i); + plots[i] = ncplot_create(planes[i], &popts); + } char32_t r; ncinput ni; // FIXME launch ticker thread @@ -48,13 +56,14 @@ int main(void){ return EXIT_FAILURE; } const uint64_t sec = (timespec_to_ns(&now) - timespec_to_ns(&start)) / NANOSECS_IN_SEC; - if(ncplot_add_sample(plot, sec, 1)){ - return EXIT_FAILURE; + for(auto i = 0u ; i < plots.size() ; ++i){ + if(ncplot_add_sample(plots[i], sec, 1)){ + return EXIT_FAILURE; + } } if(!nc.render()){ return EXIT_FAILURE; } } - ncplot_destroy(plot); return EXIT_SUCCESS; } diff --git a/src/lib/plot.c b/src/lib/plot.c index 590a0713a..7a3335141 100644 --- a/src/lib/plot.c +++ b/src/lib/plot.c @@ -1,5 +1,27 @@ #include "internal.h" +static const struct { + ncgridgeom_e geom; + const wchar_t* egcs; +} geomdata[] = { + { .geom = NCPLOT_1x1, .egcs = L"█", }, + { .geom = NCPLOT_1x1x4, .egcs = L"▒░▓█", }, + { .geom = NCPLOT_2x1, .egcs = L"▄█", }, +}; + +/* FIXME + NCPLOT_2x1TB, // full/upper blocks █▀ + NCPLOT_2x1BT, // full/lower blocks + NCPLOT_1x2LR, // left/full blocks ▌█ + NCPLOT_1x2RL, // right/full blocks █▐ + NCPLOT_2x2, // quadrants ▖▘▝▗ + NCPLOT_4x1, // four vert levels █▆▄▂ + NCPLOT_1x4, // four horizontal levels ▎▌▊█ + NCPLOT_8x1, // eight vert levels █▇▆▅▄▃▂▁ + NCPLOT_1x8, // eight horizontal levels ▏▎▍▌▋▊▉█ + NCPLOT_4x2, // 4 rows, 2 cols (braille) ...etc... +*/ + ncplot* ncplot_create(ncplane* n, const ncplot_options* opts){ // detectdomain requires that miny == maxy if(opts->detectdomain && opts->miny != opts->maxy){ @@ -8,6 +30,9 @@ ncplot* ncplot_create(ncplane* n, const ncplot_options* opts){ if(opts->maxy < opts->miny){ return NULL; } + if(opts->gridtype < 0 || opts->gridtype >= sizeof(geomdata) / sizeof(*geomdata)){ + return NULL; + } int sdimy, sdimx; ncplane_dim_yx(n, &sdimy, &sdimx); if(sdimx <= 0){ @@ -119,23 +144,38 @@ static int redraw_plot(ncplot* n){ ncplane_erase(ncplot_plane(n)); // FIXME shouldn't need this const int dimy = ncplane_dim_y(ncplot_plane(n)); - // each row is worth this much change in value - double interval = (n->maxy - n->miny + 1) / (double)dimy; + // each transition is worth this much change in value + const size_t states = wcslen(geomdata[n->gridtype].egcs); + double interval = (n->maxy - n->miny + 1) / ((double)dimy * states); int idx = n->slotstart; for(uint64_t x = 0 ; x < n->slotcount ; ++x){ - int64_t gval = n->slots[idx]; + int64_t gval = n->slots[idx]; // clip the value at the limits of the graph if(gval < n->miny){ gval = n->miny; } if(gval > n->maxy){ gval = n->maxy; } + // starting from the least-significant row, progress in the more significant + // direction, drawing egcs from the grid specification, aborting early if + // we can't draw anything in a given cell. for(int y = 0 ; y < dimy ; ++y){ - if(n->miny + interval * (y + 1) <= gval){ - if(ncplane_putegc_yx(ncplot_plane(n), dimy - y - 1, x, "█", NULL) <= 0){ - return -1; - } - }else{ + // if we've got at least one interval's worth on the number of positions + // times the number of intervals per position plus the starting offset, + // we're going to print *something* + if(n->miny + (interval * states) * y + interval > gval){ + break; + } + size_t egcidx = (gval - n->miny) - (y * interval * states) - 1; + if(egcidx >= states){ + egcidx = states - 1; + } + if(ncplane_putwc_yx(ncplot_plane(n), dimy - y - 1, x, geomdata[n->gridtype].egcs[egcidx]) <= 0){ + return -1; + } + // FIXME this ought fall out naturally. that it does not indicates, i + // think, an error above... + if(egcidx != states - 1){ break; } }